AWS SDK

AWS SDK

rev. 7a81c738582b03212f62160d093a63f8547fc0f5 (ignoring whitespace)

Files changed:

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/client/pool/admission/reuse.rs

@@ -12,12 +72,72 @@
   32     32   
//! Resolving -- repeated candidate handoff ------------------> Resolving
   33     33   
//! Resolving -- borrow or reclaim completes ------------------> removed
   34     34   
//! ```
   35     35   
//!
   36     36   
//! A sender extracted during installation takes the `Resolving` path even if
   37     37   
//! cancellation raced with the install acknowledgement. The extracted sender
   38     38   
//! must complete its terminal transition before cancellation can finish.
   39     39   
   40     40   
use super::{
   41     41   
    AdmissionAction, DeliveryAckResult, DeliveryGuard, DeliveryId, DemandId, DemandSchedule,
   42         -
    IntrusiveLinks, IntrusiveOrder, OriginAdmission, ProtocolRequirement,
          42  +
    IntrusiveLinks, IntrusiveOrder, OriginAdmission,
   43     43   
};
   44     44   
use crate::client::pool::cell::h1::{H1Selection, ProvisionalH1};
   45     45   
use crate::client::pool::cell::OriginCell;
   46     46   
use crate::client::pool::partition::{EligibilityGroup, PartitionId};
   47     47   
use crate::sync::Arc;
   48     48   
use aws_smithy_runtime_api::client::connection::ConnectionId;
   49     49   
use std::collections::{HashMap, VecDeque};
   50     50   
use std::fmt;
   51     51   
   52     52   
/// Identity of one cross-cell HTTP/1 reuse operation.
@@ -339,339 +430,426 @@
  359    359   
        if record.phase == ReusePhase::Installed {
  360    360   
            record.phase = ReusePhase::Cancelling;
  361    361   
            self.cancellations.push_back(reuse_id);
  362    362   
        }
  363    363   
        self.assert_consistent();
  364    364   
    }
  365    365   
  366    366   
    /// Selects another cell's connection for the oldest origin-wide demand.
  367    367   
    ///
  368    368   
    /// An eligible cell lends its sender. Otherwise, a connection is reclaimed
  369         -
    /// so its capacity can satisfy the same demand. A cell is never selected for
  370         -
    /// its own demand; local idle and returning senders are handled under the
  371         -
    /// cell lock.
         369  +
    /// so its capacity can satisfy the same demand. HTTP/1-compatible demand
         370  +
    /// does not select its own cell because local senders are handled under the
         371  +
    /// cell lock. HTTP/2-only demand may reclaim same-cell idle HTTP/1 capacity.
  372    372   
    pub(super) fn prepare_reuse(
  373    373   
        &mut self,
  374    374   
        schedule: &DemandSchedule,
  375    375   
    ) -> Option<PreparedReuseInstall> {
  376    376   
        let requesting_partition = schedule.queued_head()?;
  377    377   
        if self
  378    378   
            .requesting_partitions
  379    379   
            .contains_key(&requesting_partition.requesting_partition)
  380    380   
        {
  381    381   
            return None;
  382    382   
        }
  383    383   
  384         -
        let (connection_partition, mode) =
  385         -
            if requesting_partition.requirement == ProtocolRequirement::H1Compatible {
         384  +
        let (connection_partition, mode) = if requesting_partition.requirement.accepts_h1() {
  386    385   
            match self.take_group_peer(
  387    386   
                &requesting_partition.eligibility_group,
  388    387   
                &requesting_partition.requesting_partition,
  389    388   
            ) {
  390    389   
                Some(connection_partition) => (connection_partition, ReuseMode::Borrow),
  391    390   
                None => (
  392    391   
                    self.take_origin_peer(&requesting_partition.requesting_partition)?,
  393    392   
                    ReuseMode::Reclaim,
  394    393   
                ),
  395    394   
            }
  396    395   
        } else {
  397         -
                (
  398         -
                    self.take_origin_peer(&requesting_partition.requesting_partition)?,
  399         -
                    ReuseMode::Reclaim,
  400         -
                )
         396  +
            (self.take_origin_head()?, ReuseMode::Reclaim)
  401    397   
        };
  402    398   
  403    399   
        let id = self.take_reuse_id();
  404    400   
        let availability_record = self
  405    401   
            .connection_partitions
  406    402   
            .get_mut(&connection_partition)
  407    403   
            .expect("selected HTTP/1 connection cell disappeared");
  408    404   
        debug_assert!(availability_record.reuse_id.is_none());
  409    405   
        availability_record.reuse_id = Some(id);
  410    406   
        self.requesting_partitions
@@ -540,536 +599,602 @@
  560    556   
    fn take_origin_peer(&mut self, requesting_partition: &PartitionId) -> Option<PartitionId> {
  561    557   
        let connection_partition = self.first_peer(
  562    558   
            &self.origin_order,
  563    559   
            requesting_partition,
  564    560   
            AvailabilityOrderView::Reclaim,
  565    561   
        )?;
  566    562   
        self.unlink_cell(&connection_partition);
  567    563   
        Some(connection_partition)
  568    564   
    }
  569    565   
         566  +
    /// Removes and returns the oldest origin-wide connection, including local.
         567  +
    fn take_origin_head(&mut self) -> Option<PartitionId> {
         568  +
        let connection_partition = self.origin_order.head()?;
         569  +
        self.unlink_cell(&connection_partition);
         570  +
        Some(connection_partition)
         571  +
    }
         572  +
  570    573   
    /// Returns the head, or its successor when the head is the requesting cell itself.
  571    574   
    fn first_peer(
  572    575   
        &self,
  573    576   
        order: &IntrusiveOrder<PartitionId>,
  574    577   
        requesting_partition: &PartitionId,
  575    578   
        view: AvailabilityOrderView,
  576    579   
    ) -> Option<PartitionId> {
  577    580   
        let head = order.head()?;
  578    581   
        if head != *requesting_partition {
  579    582   
            return Some(head);
@@ -670,673 +731,739 @@
  690    693   
        let value = self.next_reuse;
  691    694   
        self.next_reuse = value
  692    695   
            .checked_add(1)
  693    696   
            .expect("HTTP/1 reuse operation identity exhausted");
  694    697   
        ReuseId(value)
  695    698   
    }
  696    699   
  697    700   
    /// Checks reuse-operation indexes and both availability orders after every mutation.
  698    701   
    fn assert_consistent(&self) {
  699    702   
        #[cfg(debug_assertions)]
         703  +
        {
         704  +
            if std::thread::panicking() {
         705  +
                return;
         706  +
            }
  700    707   
            self.assert_consistent_debug();
  701    708   
        }
         709  +
    }
  702    710   
  703    711   
    #[cfg(debug_assertions)]
  704    712   
    fn assert_consistent_debug(&self) {
  705    713   
        for (id, operation) in &self.operations {
  706    714   
            assert_eq!(
  707    715   
                self.requesting_partitions
  708    716   
                    .get(&operation.requesting_partition),
  709    717   
                Some(id),
  710    718   
                "reuse operation's requesting-cell index did not name the operation"
  711    719   
            );
@@ -1195,1203 +1263,1275 @@
 1215   1223   
                    .is_current_queued(&record.requesting_partition, record.demand)
 1216   1224   
            {
 1217   1225   
                drop(state);
 1218   1226   
                drop(candidate);
 1219   1227   
                return None;
 1220   1228   
            }
 1221   1229   
 1222   1230   
            match record.mode {
 1223   1231   
                ReuseMode::Borrow => {
 1224   1232   
                    let delivery = state.take_delivery_id();
        1233  +
                    let old_group = state
        1234  +
                        .demand_schedule
        1235  +
                        .group_for(&record.requesting_partition);
 1225   1236   
                    let Some(scheduled) = state.demand_schedule.reserve_reuse_demand(
 1226   1237   
                        &record.requesting_partition,
 1227   1238   
                        record.demand,
 1228   1239   
                        delivery,
 1229   1240   
                    ) else {
 1230   1241   
                        drop(state);
 1231   1242   
                        drop(candidate);
 1232   1243   
                        return None;
 1233   1244   
                    };
        1245  +
                    state.reconcile_demand_indexes(&scheduled.requesting_partition, old_group);
 1234   1246   
                    Some(AdmissionAction::Delivery(DeliveryGuard::borrowed_h1(
 1235   1247   
                        origin.clone(),
 1236   1248   
                        delivery,
 1237   1249   
                        scheduled.requesting_partition,
 1238   1250   
                        scheduled.demand,
 1239   1251   
                        id,
 1240   1252   
                        record.connection_partition,
 1241   1253   
                        candidate,
 1242   1254   
                    )))
 1243   1255   
                }
@@ -1272,1284 +1332,1344 @@
 1292   1304   
            reuse_id,
 1293   1305   
            rejected_outcome.expect("rejected borrow had no connection cell outcome"),
 1294   1306   
        );
 1295   1307   
        Self::prepare_action(origin, &mut state)
 1296   1308   
    }
 1297   1309   
}
 1298   1310   
 1299   1311   
#[cfg(all(test, not(smithy_http_client_loom)))]
 1300   1312   
mod tests {
 1301   1313   
    use super::*;
 1302         -
    use crate::client::pool::admission::{DemandSnapshot, SnapshotVersion};
        1314  +
    use crate::client::pool::admission::{DemandSnapshot, ProtocolRequirement, SnapshotVersion};
 1303   1315   
    use crate::client::pool::partition::PartitionId;
 1304   1316   
 1305   1317   
    fn cell(index: usize) -> PartitionId {
 1306   1318   
        PartitionId::from_index(index)
 1307   1319   
    }
 1308   1320   
 1309   1321   
    fn schedule(requesting_partition: PartitionId, group: EligibilityGroup) -> DemandSchedule {
 1310   1322   
        let mut schedule = DemandSchedule::default();
 1311   1323   
        schedule.publish(
 1312   1324   
            requesting_partition,
@@ -1348,1360 +1407,1451 @@
 1368   1380   
        assert_eq!(
 1369   1381   
            0,
 1370   1382   
            coordination
 1371   1383   
                .group_orders
 1372   1384   
                .get(&group)
 1373   1385   
                .expect("connection cell group disappeared")
 1374   1386   
                .len()
 1375   1387   
        );
 1376   1388   
    }
 1377   1389   
        1390  +
    #[test]
        1391  +
    fn h2_required_demand_reclaims_local_h1_capacity() {
        1392  +
        let requesting_partition = cell(1);
        1393  +
        let group = EligibilityGroup::Pool;
        1394  +
        let mut schedule = DemandSchedule::default();
        1395  +
        schedule.publish(
        1396  +
            requesting_partition,
        1397  +
            DemandSnapshot::active(
        1398  +
                DemandId::from_u64(1),
        1399  +
                SnapshotVersion::INITIAL,
        1400  +
                ProtocolRequirement::H2Required,
        1401  +
                group.clone(),
        1402  +
            ),
        1403  +
        );
        1404  +
        let mut coordination = H1Reuse::default();
        1405  +
        coordination.update_availability(
        1406  +
            requesting_partition,
        1407  +
            group,
        1408  +
            availability_snapshot(1, true, false),
        1409  +
        );
        1410  +
        1411  +
        let prepared = coordination
        1412  +
            .prepare_reuse(&schedule)
        1413  +
            .expect("local HTTP/1 capacity was not selected for reclaim");
        1414  +
        1415  +
        assert_eq!(requesting_partition, prepared.connection_partition);
        1416  +
        assert_eq!(
        1417  +
            ReuseMode::Reclaim,
        1418  +
            coordination.operations[&prepared.id].mode
        1419  +
        );
        1420  +
    }
        1421  +
 1378   1422   
    #[test]
 1379   1423   
    fn reuse_selection_skips_the_requesting_cell() {
 1380   1424   
        let requesting_partition = cell(1);
 1381   1425   
        let peer = cell(2);
 1382   1426   
        let group = EligibilityGroup::Pool;
 1383   1427   
        let mut coordination = H1Reuse::default();
 1384   1428   
        coordination.update_availability(
 1385   1429   
            requesting_partition,
 1386   1430   
            group.clone(),
 1387   1431   
            availability_snapshot(1, true, false),

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/client/pool/builder.rs

@@ -1,1 +43,44 @@
    2      2   
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    3      3   
 * SPDX-License-Identifier: Apache-2.0
    4      4   
 */
    5      5   
    6      6   
//! Construction and validation for [`ConnectionPool`].
    7      7   
    8      8   
use super::establish::{self, TransportFactory};
    9      9   
use super::maintenance::MaintenanceConfig;
   10     10   
use super::registry::{PartitionRegistry, PartitionRegistryError};
   11     11   
use super::{ConnectionPool, ConnectionReuseScope, Partition, PoolConfig, PoolInner};
   12         -
use crate::client::TlsUnset;
          12  +
use crate::client::{TlsProviderSelected, TlsUnset};
   13     13   
use crate::sync::Arc;
          14  +
use crate::tls::{self, TlsContext};
   14     15   
use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep, SharedAsyncSleep};
   15     16   
use aws_smithy_async::time::{SharedTimeSource, TimeSource};
   16     17   
#[cfg(any(
   17     18   
    all(test, feature = "rt-tokio"),
   18     19   
    all(feature = "test-util", aws_sdk_unstable)
   19     20   
))]
   20     21   
use aws_smithy_runtime_api::box_error::BoxError;
   21     22   
#[cfg(any(
   22     23   
    all(test, feature = "rt-tokio"),
   23     24   
    all(feature = "test-util", aws_sdk_unstable)
@@ -213,214 +361,462 @@
  233    234   
        self
  234    235   
    }
  235    236   
  236    237   
    /// Mutably declares or clears the explicit partition set.
  237    238   
    pub fn set_partitions(&mut self, partitions: Option<Vec<Partition>>) -> &mut Self {
  238    239   
        self.partitions = partitions;
  239    240   
        self
  240    241   
    }
  241    242   
}
  242    243   
         244  +
impl Builder<TlsUnset> {
         245  +
    /// Selects the TLS provider used by HTTPS pool connections.
         246  +
    pub fn tls_provider(self, provider: tls::Provider) -> Builder<TlsProviderSelected> {
         247  +
        Builder {
         248  +
            idle_timeout: self.idle_timeout,
         249  +
            time_source: self.time_source,
         250  +
            sleep_impl: self.sleep_impl,
         251  +
            tcp_nodelay: self.tcp_nodelay,
         252  +
            tcp_keepalive: self.tcp_keepalive,
         253  +
            max_connections_per_host: self.max_connections_per_host,
         254  +
            reuse_scope: self.reuse_scope,
         255  +
            partitions: self.partitions,
         256  +
            tls: TlsProviderSelected {
         257  +
                provider,
         258  +
                context: TlsContext::default(),
         259  +
            },
         260  +
        }
         261  +
    }
         262  +
}
         263  +
         264  +
crate::cfg::cfg_tls! {
         265  +
    impl Builder<TlsProviderSelected> {
         266  +
        /// Sets provider-specific TLS configuration for HTTPS connections.
         267  +
        pub fn tls_context(mut self, context: TlsContext) -> Self {
         268  +
            self.tls.context = context;
         269  +
            self
         270  +
        }
         271  +
         272  +
        /// Mutably sets provider-specific TLS configuration.
         273  +
        pub fn set_tls_context(&mut self, context: TlsContext) -> &mut Self {
         274  +
            self.tls.context = context;
         275  +
            self
         276  +
        }
         277  +
         278  +
        /// Builds a pool whose connector performs TLS and ALPN negotiation.
         279  +
        ///
         280  +
        /// This builder currently creates direct connections. Proxy routing
         281  +
        /// remains available through the existing `Connector` API.
         282  +
        pub fn build_https(self) -> Result<ConnectionPool, BuildError> {
         283  +
            validate_default_connector_interfaces(self.partitions.as_deref())?;
         284  +
            let provider = self.tls.provider.clone();
         285  +
            let context = self.tls.context.clone();
         286  +
            match provider {
         287  +
                #[cfg(feature = "__rustls")]
         288  +
                tls::Provider::Rustls(crypto_mode) => {
         289  +
                    let tcp_nodelay = self.tcp_nodelay;
         290  +
                    let tcp_keepalive = self.tcp_keepalive.clone().resolve(None);
         291  +
                    let transport = establish::cached_transport_factory_for_interface(
         292  +
                        move |interface, alpn_protocols| {
         293  +
                            let mut connector =
         294  +
                                HttpConnector::new_with_resolver(GaiResolver::new());
         295  +
                            connector.set_nodelay(tcp_nodelay);
         296  +
                            connector.set_keepalive(tcp_keepalive);
         297  +
                            set_default_connector_interface(&mut connector, interface);
         298  +
                            tls::rustls_provider::build_connector::wrap_connector_with_alpn(
         299  +
                                connector,
         300  +
                                crypto_mode.clone(),
         301  +
                                &context,
         302  +
                                crate::proxy::ProxyConfig::disabled(),
         303  +
                                alpn_protocols,
         304  +
                            )
         305  +
                        },
         306  +
                        true,
         307  +
                    );
         308  +
                    self.build_with_transport(transport)
         309  +
                }
         310  +
                #[cfg(feature = "s2n-tls")]
         311  +
                tls::Provider::S2nTls => {
         312  +
                    let tcp_nodelay = self.tcp_nodelay;
         313  +
                    let tcp_keepalive = self.tcp_keepalive.clone().resolve(None);
         314  +
                    let transport = establish::cached_transport_factory_for_interface(
         315  +
                        move |interface, _alpn_protocols| {
         316  +
                            let mut connector =
         317  +
                                HttpConnector::new_with_resolver(GaiResolver::new());
         318  +
                            connector.set_nodelay(tcp_nodelay);
         319  +
                            connector.set_keepalive(tcp_keepalive);
         320  +
                            set_default_connector_interface(&mut connector, interface);
         321  +
                            tls::s2n_tls_provider::build_connector::wrap_connector(
         322  +
                                connector,
         323  +
                                &context,
         324  +
                                crate::proxy::ProxyConfig::disabled(),
         325  +
                            )
         326  +
                        },
         327  +
                        false,
         328  +
                    );
         329  +
                    self.build_with_transport(transport)
         330  +
                }
         331  +
            }
         332  +
        }
         333  +
    }
         334  +
}
         335  +
  243    336   
impl Builder<TlsUnset> {
  244    337   
    /// Builds a pool for cleartext HTTP connections.
         338  +
    ///
         339  +
    /// This method remains public for explicit cleartext endpoints and tests,
         340  +
    /// but is hidden from generated documentation because HTTPS with automatic
         341  +
    /// ALPN negotiation is the intended production entry point.
  245    342   
    #[doc(hidden)]
  246    343   
    pub fn build_http(self) -> Result<ConnectionPool, BuildError> {
  247    344   
        validate_default_connector_interfaces(self.partitions.as_deref())?;
  248    345   
        let mut connector = HttpConnector::new_with_resolver(GaiResolver::new());
  249    346   
        connector.set_nodelay(self.tcp_nodelay);
  250    347   
        connector.set_keepalive(self.tcp_keepalive.clone().resolve(None));
  251    348   
        let transport = establish::transport_factory_for_interface(move |interface| {
  252    349   
            let mut connector = connector.clone();
  253    350   
            set_default_connector_interface(&mut connector, interface);
  254    351   
            connector
  255    352   
        });
  256    353   
        self.build_with_transport(transport)
  257    354   
    }
  258    355   
  259    356   
    /// Builds a pool around a test transport connector.
  260    357   
    #[cfg(all(feature = "test-util", aws_sdk_unstable))]
  261    358   
    #[doc(hidden)]
  262    359   
    pub fn build_http_with_tcp_connector<C, IO>(
  263    360   
        self,
  264    361   
        connector: C,
  265    362   
    ) -> Result<ConnectionPool, BuildError>
  266    363   
    where
  267    364   
        C: Service<Uri, Response = IO> + Clone + Send + Sync + 'static,
  268    365   
        C::Error: Into<BoxError>,
  269    366   
        C::Future: Send + 'static,
  270    367   
        IO: hyper::rt::Read
  271    368   
            + hyper::rt::Write
  272    369   
            + hyper_util::client::legacy::connect::Connection
  273    370   
            + Send
  274    371   
            + Sync
  275    372   
            + Unpin
  276    373   
            + 'static,
  277    374   
    {
  278    375   
        self.build_with_transport(establish::transport_factory(connector))
  279    376   
    }
  280    377   
  281    378   
    #[cfg(all(test, feature = "rt-tokio"))]
  282    379   
    pub(super) fn build_with_connector<C, IO>(
  283    380   
        self,
  284    381   
        connector: C,
  285    382   
    ) -> Result<ConnectionPool, BuildError>
  286    383   
    where
  287    384   
        C: Service<Uri, Response = IO> + Clone + Send + Sync + 'static,
  288    385   
        C::Error: Into<BoxError>,
  289    386   
        C::Future: Send + 'static,
  290    387   
        IO: hyper::rt::Read
  291    388   
            + hyper::rt::Write
  292    389   
            + hyper_util::client::legacy::connect::Connection
  293    390   
            + Send
  294    391   
            + Sync
  295    392   
            + Unpin
  296    393   
            + 'static,
  297    394   
    {
  298    395   
        self.build_with_transport(establish::transport_factory(connector))
  299    396   
    }
         397  +
}
  300    398   
         399  +
impl<Tls> Builder<Tls> {
  301    400   
    /// Validates pool policy and installs the type-erased transport factory.
  302    401   
    fn build_with_transport(
  303    402   
        self,
  304    403   
        transport: std::sync::Arc<dyn TransportFactory>,
  305    404   
    ) -> Result<ConnectionPool, BuildError> {
  306    405   
        let max_connections_per_host = match self.max_connections_per_host {
  307    406   
            Some(0) => {
  308    407   
                return Err(BuildError::new(
  309    408   
                    "max_connections_per_host must be greater than zero",
  310    409   
                ))
  311    410   
            }
  312    411   
            Some(limit) => NonZeroUsize::new(limit),
  313    412   
            None => None,
  314    413   
        };
  315    414   
        let idle_timeout = self.idle_timeout.resolve(Some(DEFAULT_IDLE_TIMEOUT));
  316    415   
        let time_source = self.time_source.unwrap_or_default();
  317    416   
        let sleep_impl = self.sleep_impl.or_else(default_async_sleep);
  318    417   
        if idle_timeout.is_some() && sleep_impl.is_none() {
  319    418   
            return Err(BuildError::new(
  320    419   
                "idle_timeout requires an async sleep implementation",
  321    420   
            ));
  322    421   
        }
  323    422   
        let maintenance = MaintenanceConfig {
  324    423   
            idle_timeout,
  325    424   
            time_source: time_source.clone(),
  326    425   
            sleep: sleep_impl.clone(),
  327    426   
        };
         427  +
        let allow_h2_reclaim_for_h1 = transport.guarantees_http1();
  328    428   
        let registry = PartitionRegistry::new(
  329    429   
            self.partitions,
  330    430   
            self.reuse_scope,
  331    431   
            max_connections_per_host,
         432  +
            allow_h2_reclaim_for_h1,
  332    433   
            maintenance,
  333    434   
        )
  334    435   
        .map_err(BuildError::from)?;
  335    436   
        let config = PoolConfig {
  336    437   
            idle_timeout,
  337    438   
            max_connections_per_host,
  338    439   
            reuse_scope: self.reuse_scope,
  339    440   
        };
  340    441   
        Ok(ConnectionPool {
  341    442   
            inner: Arc::new(PoolInner {

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/client/pool/cell.rs

@@ -1,1 +188,256 @@
    6      6   
//! State local to one partition and origin.
    7      7   
//!
    8      8   
//! An [`OriginCell`] owns its acquisition order and protocol records. A
    9      9   
//! bounded cell publishes aggregate demand to [`OriginAdmission`] after
   10     10   
//! releasing its lock, and admission returns capacity through the same
   11     11   
//! unlocked boundary.
   12     12   
//!
   13     13   
//! [`AcquisitionQueue`] owns every live acquisition attempt, including the
   14     14   
//! bounded FIFO, delivery crossings, establishment launch, cancellation, and
   15     15   
//! terminal results. Its module documents the complete transition model.
   16         -
//! [`CellState`] couples that model to HTTP/1 sender residence so a local
   17         -
//! return either satisfies one acquisition or becomes idle, never both.
          16  +
//! [`CellState`] couples that model to HTTP/1 sender residence, HTTP/2
          17  +
//! flight and generation residence, generation gates, and the cross-cell reuse
          18  +
//! reservation. A local HTTP/1 return either satisfies one acquisition or
          19  +
//! becomes idle, never both. An HTTP/2 activation becomes visible only with a
          20  +
//! prospective generation lease and one recorded gate opportunity.
   18     21   
//!
   19     22   
//! Permits, senders, admission updates, and task wakes are detached from
   20     23   
//! mutable state before their fallback or callback runs. This keeps drop and
   21     24   
//! wake paths outside the cell lock.
   22     25   
   23     26   
pub(super) mod h1;
          27  +
pub(super) mod h2;
   24     28   
mod waiters;
   25     29   
   26     30   
#[cfg(test)]
   27     31   
use self::h1::H1CloseHandle;
   28     32   
#[cfg(all(test, not(smithy_http_client_loom)))]
   29     33   
use self::h1::H1DriverGuard;
   30         -
use self::h1::{H1Records, H1ReuseReservation, H1Selection, H1Sender, OwnedH1, ProvisionalH1};
          34  +
#[cfg(test)]
          35  +
use self::h1::H1Sender;
          36  +
use self::h1::{H1Records, H1ReuseReservation, H1Selection, OwnedH1};
   31     37   
#[cfg(test)]
   32     38   
use self::waiters::CellSnapshot;
   33     39   
pub(in crate::client::pool) use self::waiters::WaiterId;
   34     40   
use self::waiters::{AcquisitionQueue, DeliveryReservation, ResultInstallError};
   35         -
use super::admission::reuse::{
   36         -
    H1Availability, H1AvailabilitySnapshot, PreparedReuseInstall, ReuseCandidate, ReuseId,
   37         -
    ReuseInstallResult,
   38         -
};
   39         -
#[cfg(test)]
   40         -
use super::admission::DemandSnapshot;
          41  +
use super::admission::reuse::{H1Availability, H1AvailabilitySnapshot, ReuseId};
   41     42   
use super::admission::{
   42         -
    AdmissionAction, CapacityLease, DeliveryGuard, OriginAdmission, ProtocolRequirement,
          43  +
    AdmissionAction, CapacityLease, DeliveryGuard, DemandSnapshot, H2AdvertisementSnapshot,
          44  +
    OriginAdmission, ProtocolRequirement,
   43     45   
};
          46  +
use super::connection::CloseReason;
   44     47   
#[cfg(test)]
   45     48   
use super::connection::ConnectionInfo;
   46         -
use super::connection::{CloseReason, ConnectionState};
          49  +
#[cfg(test)]
          50  +
use super::connection::ConnectionState;
   47     51   
use super::maintenance::PartitionMaintenance;
   48     52   
use super::origin::OriginKey;
   49     53   
use super::partition::{EligibilityGroup, PartitionId};
   50     54   
use crate::sync::{Arc, Mutex};
          55  +
#[cfg(test)]
   51     56   
use aws_smithy_runtime_api::client::connection::ConnectionId;
   52     57   
use aws_smithy_runtime_api::client::result::ConnectorError;
   53     58   
use std::task::{Context, Poll};
   54     59   
use std::time::SystemTime;
   55     60   
   56     61   
/// Stable identity of an [`OriginCell`].
   57     62   
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
   58     63   
pub(crate) struct CellId {
   59     64   
    /// Partition that owns this cell's connection work.
   60     65   
    partition: PartitionId,
   61     66   
    /// Canonical origin whose requests share this cell.
   62     67   
    origin: OriginKey,
   63     68   
}
   64     69   
   65     70   
impl CellId {
   66     71   
    pub(super) fn new(partition: PartitionId, origin: OriginKey) -> Self {
   67     72   
        Self { partition, origin }
   68     73   
    }
   69     74   
   70     75   
    pub(crate) fn partition(&self) -> PartitionId {
   71     76   
        self.partition
   72     77   
    }
   73     78   
   74     79   
    pub(crate) fn origin(&self) -> &OriginKey {
   75     80   
        &self.origin
   76     81   
    }
   77     82   
}
   78     83   
   79     84   
/// Stable state shared by requests for one partition and canonical origin.
   80     85   
pub(crate) struct OriginCell {
   81     86   
    /// Complete identity used by partition and admission indexes.
   82     87   
    id: CellId,
   83     88   
    /// Partitions whose connections may satisfy this cell's demand.
   84     89   
    eligibility_group: EligibilityGroup,
   85     90   
    /// Origin-wide authority present only when capacity is bounded.
   86     91   
    admission: Option<Arc<OriginAdmission>>,
   87     92   
    /// Partition-owned idle deadline scheduler.
   88     93   
    maintenance: Option<Arc<PartitionMaintenance>>,
   89     94   
    /// Waiter order and protocol records protected by one cell-local lock.
   90     95   
    state: Mutex<CellState>,
   91     96   
}
   92     97   
   93     98   
/// Mutable state protected by one partition-origin cell lock.
   94     99   
///
   95         -
/// Waiter outcomes and HTTP/1 residence share this lock so a returning sender
   96         -
/// either becomes visible to one waiter or enters idle storage, never both.
         100  +
/// Waiter outcomes and protocol residence share this lock. HTTP/1 returns,
         101  +
/// HTTP/2 activation gates, flight participants, and cancellation therefore
         102  +
/// commit against one acquisition order.
   97    103   
#[derive(Debug, Default)]
   98    104   
struct CellState {
   99    105   
    /// Cell-local acquisition order and delivered results.
  100    106   
    waiters: AcquisitionQueue,
  101    107   
    /// Cell-owned HTTP/1 records and reusable sender order.
  102    108   
    h1: H1Records,
         109  +
    /// Cell-owned HTTP/2 flight and installed generations.
         110  +
    h2: h2::H2Records,
  103    111   
    /// One cross-cell reuse reservation and its local fairness debt.
  104    112   
    reuse: H1ReuseReservation,
  105    113   
    /// Last HTTP/1 availability published to bounded-origin admission.
  106    114   
    published_h1_availability: Option<H1Availability>,
  107    115   
    /// Revision used to reject availability reports that cross out of order.
  108    116   
    h1_availability_revision: u64,
         117  +
    /// Last complete H2 advertisement reported to origin admission.
         118  +
    published_h2_advertisement: Option<(h2::H2GenerationId, bool)>,
         119  +
    /// Revision used to reject H2 advertisements that cross out of order.
         120  +
    h2_advertisement_revision: u64,
  109    121   
}
  110    122   
  111    123   
impl CellState {
  112    124   
    /// Checks the coupled waiter, sender, and reuse-reservation state machines.
  113    125   
    fn assert_consistent(&self) {
         126  +
        #[cfg(any(debug_assertions, test))]
         127  +
        if std::thread::panicking() {
         128  +
            return;
         129  +
        }
  114    130   
        self.waiters.assert_consistent();
  115    131   
        self.h1.assert_consistent();
         132  +
        self.h2.assert_consistent();
         133  +
        #[cfg(any(debug_assertions, test))]
         134  +
        self.h2.assert_pending_waiters(&self.waiters);
  116    135   
        self.reuse
  117    136   
            .assert_consistent(self.h1.supports_installed_reuse());
  118    137   
    }
  119    138   
  120    139   
    /// Reports the HTTP/1 availability admission needs without exposing cell internals.
  121    140   
    fn h1_availability(&self) -> H1Availability {
  122    141   
        let local_h1_demand = self.waiters.can_accept_h1();
  123    142   
        H1Availability {
  124    143   
            advertised: self.h1.has_returnable(),
  125    144   
            blocked: !self.reuse.is_available()
  126    145   
                || self.reuse.blocks_peer_reuse(local_h1_demand)
  127    146   
                || self.waiters.has_prior_h1_candidate(),
  128    147   
        }
  129    148   
    }
  130    149   
  131    150   
    /// Returns an availability update only when admission's view must change.
  132    151   
    fn take_h1_availability_update(&mut self) -> Option<H1AvailabilitySnapshot> {
  133    152   
        let current = self.h1_availability();
  134    153   
        if self.published_h1_availability == Some(current) {
  135    154   
            return None;
  136    155   
        }
  137    156   
        Some(self.record_h1_availability(current))
  138    157   
    }
  139    158   
  140    159   
    /// Returns the current versioned availability for a reuse transition.
  141    160   
    fn report_h1_availability(&mut self) -> H1AvailabilitySnapshot {
  142    161   
        let current = self.h1_availability();
  143    162   
        if self.published_h1_availability == Some(current) {
  144    163   
            return H1AvailabilitySnapshot::new(self.h1_availability_revision, current);
  145    164   
        }
  146    165   
        self.record_h1_availability(current)
  147    166   
    }
  148    167   
  149    168   
    /// Advances the revision and records changed HTTP/1 availability.
  150    169   
    fn record_h1_availability(&mut self, availability: H1Availability) -> H1AvailabilitySnapshot {
  151    170   
        self.h1_availability_revision = self
  152    171   
            .h1_availability_revision
  153    172   
            .checked_add(1)
  154    173   
            .expect("HTTP/1 availability revision exhausted");
  155    174   
        self.published_h1_availability = Some(availability);
  156    175   
        H1AvailabilitySnapshot::new(self.h1_availability_revision, availability)
  157    176   
    }
  158    177   
         178  +
    /// Returns an H2 advertisement only when admission's view must change.
         179  +
    fn take_h2_advertisement_update(&mut self) -> Option<H2AdvertisementSnapshot> {
         180  +
        let current = self.h2_advertisement();
         181  +
        if self.published_h2_advertisement == current {
         182  +
            return None;
         183  +
        }
         184  +
        Some(self.record_h2_advertisement(current))
         185  +
    }
         186  +
         187  +
    /// Returns the current versioned H2 advertisement for a reclaim transition.
         188  +
    fn report_h2_advertisement(&mut self) -> H2AdvertisementSnapshot {
         189  +
        let current = self.h2_advertisement();
         190  +
        if self.published_h2_advertisement == current {
         191  +
            return Self::h2_advertisement_snapshot(self.h2_advertisement_revision, current);
         192  +
        }
         193  +
        self.record_h2_advertisement(current)
         194  +
    }
         195  +
         196  +
    /// Returns the exact publishable generation and its idle state.
         197  +
    fn h2_advertisement(&self) -> Option<(h2::H2GenerationId, bool)> {
         198  +
        self.h2
         199  +
            .publishable_generation()
         200  +
            .map(|generation| (generation, self.h2.is_idle(generation)))
         201  +
    }
         202  +
         203  +
    /// Advances the revision and records changed H2 availability.
         204  +
    fn record_h2_advertisement(
         205  +
        &mut self,
         206  +
        advertisement: Option<(h2::H2GenerationId, bool)>,
         207  +
    ) -> H2AdvertisementSnapshot {
         208  +
        self.h2_advertisement_revision = self
         209  +
            .h2_advertisement_revision
         210  +
            .checked_add(1)
         211  +
            .expect("HTTP/2 advertisement revision exhausted");
         212  +
        self.published_h2_advertisement = advertisement;
         213  +
        Self::h2_advertisement_snapshot(self.h2_advertisement_revision, advertisement)
         214  +
    }
         215  +
         216  +
    fn h2_advertisement_snapshot(
         217  +
        revision: u64,
         218  +
        advertisement: Option<(h2::H2GenerationId, bool)>,
         219  +
    ) -> H2AdvertisementSnapshot {
         220  +
        match advertisement {
         221  +
            Some((generation, true)) => H2AdvertisementSnapshot::idle(revision, generation),
         222  +
            Some((generation, false)) => H2AdvertisementSnapshot::accepting(revision, generation),
         223  +
            None => H2AdvertisementSnapshot::unavailable(revision),
         224  +
        }
         225  +
    }
         226  +
  159    227   
    /// Atomically decides whether a peer may reserve this cell's connection.
  160    228   
    fn install_reuse(&mut self, reuse_id: ReuseId) -> ReuseInstall {
  161    229   
        let local_h1_demand = self.waiters.can_accept_h1();
  162    230   
        if self.reuse.blocks_peer_reuse(local_h1_demand)
  163    231   
            || self.waiters.has_prior_h1_candidate()
  164    232   
            || !self.reuse.is_available()
  165    233   
        {
  166    234   
            let report = self.report_h1_availability();
  167    235   
            self.assert_consistent();
  168    236   
            return ReuseInstall::Rejected(report);
@@ -196,264 +1120,824 @@
  216    284   
    fn finish_reuse(&mut self, reuse_id: ReuseId, transferred: bool) -> H1AvailabilitySnapshot {
  217    285   
        if transferred {
  218    286   
            let local_h1_demand = self.waiters.can_accept_h1();
  219    287   
            self.reuse.complete_transfer(reuse_id, local_h1_demand);
  220    288   
        } else {
  221    289   
            self.reuse.reject(reuse_id);
  222    290   
        }
  223    291   
        self.assert_consistent();
  224    292   
        self.report_h1_availability()
  225    293   
    }
         294  +
         295  +
    /// Removes active HTTP/2-compatible demand already served by visible H2 state.
         296  +
    fn publishable_demand_updates(
         297  +
        &self,
         298  +
        updates: [Option<DemandSnapshot>; 2],
         299  +
    ) -> [Option<DemandSnapshot>; 2] {
         300  +
        let h2_visible = self.h2.has_visible_h2();
         301  +
        updates.map(|snapshot| {
         302  +
            snapshot
         303  +
                .filter(|snapshot| !h2_visible || !snapshot.is_active() || !snapshot.accepts_h2())
         304  +
        })
         305  +
    }
  226    306   
}
  227    307   
  228    308   
/// Cell-local result of attempting to install one peer reuse reservation.
  229    309   
enum ReuseInstall {
  230    310   
    /// The reservation will intercept a future sender return.
  231    311   
    Installed,
  232    312   
    /// An idle sender was detached for immediate resolution.
  233    313   
    Candidate(OwnedH1),
  234    314   
    /// The cell could not reserve a connection for the operation.
  235    315   
    Rejected(H1AvailabilitySnapshot),
  236    316   
}
  237    317   
  238    318   
/// A terminal result that may satisfy an acquisition waiter.
  239    319   
#[derive(Debug)]
  240    320   
pub(super) enum AcquisitionResult {
  241    321   
    /// An exclusive HTTP/1 sender selected from an installed cell-owned record.
  242    322   
    H1(H1Selection),
         323  +
    /// A prospective request lease against one HTTP/2 generation.
         324  +
    H2(h2::H2Activation),
  243    325   
    /// Establishment failed before producing a dispatchable connection.
  244    326   
    Failed(ConnectorError),
         327  +
    /// An HTTP/2 generation closed before serving a transferred attempt.
         328  +
    Reacquire,
  245    329   
}
  246    330   
  247    331   
/// One event observed while driving an acquisition attempt.
  248    332   
#[derive(Debug)]
  249    333   
pub(super) enum AcquisitionEvent {
  250    334   
    /// Capacity is available and one establishment attempt may start.
  251    335   
    Establish(EstablishmentPermit),
  252    336   
    /// A returned sender or establishment produced the terminal result.
  253    337   
    Complete(AcquisitionResult),
  254    338   
}
  255    339   
  256    340   
/// Optional bounded-origin capacity for one establishment attempt.
  257    341   
///
  258    342   
/// Unbounded origins carry no lease. For bounded origins, dropping this value
  259    343   
/// before connection installation returns the permit to admission.
  260    344   
#[derive(Debug)]
  261    345   
pub(super) struct EstablishmentPermit {
  262    346   
    /// Bounded-origin slot transferred into a connection on success.
  263    347   
    lease: Option<CapacityLease>,
  264    348   
}
  265    349   
  266    350   
impl EstablishmentPermit {
  267    351   
    /// Creates a permit for an origin without a connection bound.
  268    352   
    fn unbounded() -> Self {
  269    353   
        Self { lease: None }
  270    354   
    }
  271    355   
  272    356   
    /// Takes ownership of one bounded-origin capacity lease.
  273    357   
    pub(in crate::client::pool) fn bounded(lease: CapacityLease) -> Self {
  274    358   
        Self { lease: Some(lease) }
  275    359   
    }
  276    360   
  277    361   
    /// Transfers bounded capacity into an installed connection, when present.
  278    362   
    pub(super) fn into_lease(self) -> Option<CapacityLease> {
  279    363   
        self.lease
  280    364   
    }
  281    365   
}
  282    366   
  283    367   
impl OriginCell {
  284    368   
    /// Creates a cell before its one-time publication in a partition registry.
  285    369   
    pub(super) fn new(
  286    370   
        partition: PartitionId,
  287    371   
        origin: OriginKey,
  288    372   
        eligibility_group: EligibilityGroup,
  289    373   
        admission: Option<Arc<OriginAdmission>>,
  290    374   
        maintenance: Option<Arc<PartitionMaintenance>>,
  291    375   
    ) -> Self {
  292    376   
        Self {
  293    377   
            id: CellId::new(partition, origin),
  294    378   
            eligibility_group,
  295    379   
            admission,
  296    380   
            maintenance,
  297    381   
            state: Mutex::new(CellState::default()),
  298    382   
        }
  299    383   
    }
  300    384   
  301    385   
    /// Returns the next idle deadline from immutable pool policy.
  302         -
    fn idle_deadline(&self) -> Option<SystemTime> {
         386  +
    pub(in crate::client::pool) fn idle_deadline(&self) -> Option<SystemTime> {
  303    387   
        self.maintenance
  304    388   
            .as_ref()
  305    389   
            .and_then(|maintenance| maintenance.idle_deadline())
  306    390   
    }
  307    391   
  308    392   
    /// Publishes a newly idle deadline to partition maintenance.
  309    393   
    fn notify_maintenance(&self, deadline: Option<SystemTime>) {
  310    394   
        if let Some(maintenance) = &self.maintenance {
  311    395   
            maintenance.notify_deadline(deadline);
  312    396   
        }
  313    397   
    }
  314    398   
  315    399   
    pub(crate) fn id(&self) -> &CellId {
  316    400   
        &self.id
  317    401   
    }
  318    402   
  319    403   
    #[cfg(test)]
  320    404   
    pub(crate) fn eligibility_group(&self) -> &EligibilityGroup {
  321    405   
        &self.eligibility_group
  322    406   
    }
  323    407   
  324    408   
    #[cfg(test)]
  325    409   
    pub(crate) fn admission(&self) -> Option<&Arc<OriginAdmission>> {
  326    410   
        self.admission.as_ref()
  327    411   
    }
  328    412   
  329         -
    /// Installs a fresh H1 record selected by its launching request.
  330         -
    ///
  331         -
    /// # Panics
  332         -
    ///
  333         -
    /// Panics if this cell already contains the connection identity.
  334         -
    pub(super) fn install_selected_h1(
  335         -
        cell: &Arc<Self>,
  336         -
        connection: Arc<ConnectionState>,
  337         -
        sender: H1Sender,
  338         -
    ) -> H1Selection {
  339         -
        let (installed, availability) = {
  340         -
            let mut state = cell.state.lock();
  341         -
            let installed = state.h1.install_selected(connection, sender);
  342         -
            state.assert_consistent();
  343         -
            (installed, state.take_h1_availability_update())
  344         -
        };
  345         -
        cell.publish_h1_availability(availability);
  346         -
        match installed {
  347         -
            Ok(owner) => H1Selection::new(cell, owner),
  348         -
            Err(owner) => {
  349         -
                owner
  350         -
                    .connection()
  351         -
                    .logical_close(CloseReason::ProtocolClosed);
  352         -
                drop(owner);
  353         -
                panic!("duplicate HTTP/1 connection identity installed in one cell");
  354         -
            }
  355         -
        }
  356         -
    }
  357         -
  358         -
    /// Installs an H1 record whose launching acquisition already completed.
  359         -
    ///
  360         -
    /// # Panics
  361         -
    ///
  362         -
    /// Panics if this cell already contains the connection identity.
  363         -
    #[cfg(test)]
  364         -
    pub(super) fn install_idle_h1(
  365         -
        cell: &Arc<Self>,
  366         -
        connection: Arc<ConnectionState>,
  367         -
        sender: H1Sender,
  368         -
    ) {
  369         -
        let deadline = cell.idle_deadline();
  370         -
        let (installed, availability) = {
  371         -
            let mut state = cell.state.lock();
  372         -
            let installed = state.h1.install_idle(connection, sender, deadline);
  373         -
            state.assert_consistent();
  374         -
            (installed, state.take_h1_availability_update())
  375         -
        };
  376         -
        cell.publish_h1_availability(availability);
  377         -
        if let Err(owner) = installed {
  378         -
            owner
  379         -
                .connection()
  380         -
                .logical_close(CloseReason::ProtocolClosed);
  381         -
            drop(owner);
  382         -
            panic!("duplicate HTTP/1 connection identity installed in one cell");
  383         -
        }
  384         -
        cell.notify_maintenance(deadline);
  385         -
    }
  386         -
  387         -
    /// Selects the newest reusable H1 sender without origin-wide coordination.
  388         -
    pub(super) fn select_h1(cell: &Arc<Self>) -> Option<H1Selection> {
  389         -
        let (owner, availability) = {
  390         -
            let mut state = cell.state.lock();
  391         -
            let owner = state.h1.select_idle();
  392         -
            if owner.is_some() {
  393         -
                state.reuse.consume_local_turn();
  394         -
            }
  395         -
            state.assert_consistent();
  396         -
            let availability = cell
  397         -
                .admission
  398         -
                .as_ref()
  399         -
                .and_then(|_| state.take_h1_availability_update());
  400         -
            (owner, availability)
  401         -
        };
  402         -
        cell.publish_h1_availability(availability);
  403         -
        let owner = owner?;
  404         -
        Some(H1Selection::new(cell, owner))
  405         -
    }
  406         -
  407         -
    /// Reserves this cell's selected connection for one peer reuse operation.
  408         -
    pub(in crate::client::pool) fn install_h1_reuse(
  409         -
        cell: &Arc<Self>,
  410         -
        origin: Arc<OriginAdmission>,
  411         -
        prepared: PreparedReuseInstall,
  412         -
    ) -> Option<AdmissionAction> {
  413         -
        let decision = {
  414         -
            let mut state = cell.state.lock();
  415         -
            state.install_reuse(prepared.id)
  416         -
        };
  417         -
  418         -
        let result = match decision {
  419         -
            ReuseInstall::Installed => ReuseInstallResult::Installed,
  420         -
            ReuseInstall::Candidate(owner) => {
  421         -
                let provisional = ProvisionalH1::new(cell, owner);
  422         -
                ReuseInstallResult::Candidate(ReuseCandidate::new(
  423         -
                    origin.clone(),
  424         -
                    prepared.id,
  425         -
                    cell.id.partition(),
  426         -
                    provisional,
  427         -
                ))
  428         -
            }
  429         -
            ReuseInstall::Rejected(availability) => ReuseInstallResult::Rejected(availability),
  430         -
        };
  431         -
        OriginAdmission::finish_h1_reuse_install(&origin, prepared.id, cell.id.partition(), result)
  432         -
    }
  433         -
  434         -
    /// Clears an installed or resolving reservation after request cancellation.
  435         -
    pub(in crate::client::pool) fn cancel_h1_reuse(
  436         -
        &self,
  437         -
        reuse_id: ReuseId,
  438         -
    ) -> H1AvailabilitySnapshot {
  439         -
        self.state.lock().cancel_reuse(reuse_id)
  440         -
    }
  441         -
  442         -
    /// Returns a rejected provisional sender through ordinary connection-owning cell handling.
  443         -
    pub(in crate::client::pool) fn reject_h1_reuse_candidate(
  444         -
        cell: &Arc<Self>,
  445         -
        reuse_id: ReuseId,
  446         -
        provisional: ProvisionalH1,
  447         -
    ) -> H1AvailabilitySnapshot {
  448         -
        {
  449         -
            let mut state = cell.state.lock();
  450         -
            state.reject_reuse_candidate(reuse_id);
  451         -
        }
  452         -
        drop(provisional);
  453         -
        let mut state = cell.state.lock();
  454         -
        state.assert_consistent();
  455         -
        state.report_h1_availability()
  456         -
    }
  457         -
  458         -
    /// Revalidates a reuse operation and commits its provisional sender for dispatch.
  459         -
    pub(in crate::client::pool) fn commit_h1_reuse(
  460         -
        cell: &Arc<Self>,
  461         -
        reuse_id: ReuseId,
  462         -
        provisional: ProvisionalH1,
  463         -
    ) -> Result<H1Selection, ProvisionalH1> {
  464         -
        let (connection_cell, owner) = provisional.into_parts();
  465         -
        let committed = cell.state.lock().commit_reuse(reuse_id, &owner);
  466         -
        if committed {
  467         -
            Ok(H1Selection::new(cell, owner))
  468         -
        } else {
  469         -
            Err(ProvisionalH1::from_parts(connection_cell, owner))
  470         -
        }
  471         -
    }
  472         -
  473         -
    /// Closes a selected sender and records fairness only if close wins.
  474         -
    pub(in crate::client::pool) fn reclaim_h1_reuse(
  475         -
        cell: &Arc<Self>,
  476         -
        reuse_id: ReuseId,
  477         -
        provisional: ProvisionalH1,
  478         -
    ) -> Result<(H1AvailabilitySnapshot, bool), ProvisionalH1> {
  479         -
        let (connection_cell, owner) = provisional.into_parts();
  480         -
        if !cell.state.lock().reuse.names(reuse_id) {
  481         -
            return Err(ProvisionalH1::from_parts(connection_cell, owner));
  482         -
        }
  483         -
  484         -
        let close_won = Self::retire_h1_owner(cell, owner, CloseReason::Reclaimed);
  485         -
        let availability = {
  486         -
            let mut state = cell.state.lock();
  487         -
            let availability = state.finish_reuse(reuse_id, close_won);
  488         -
            state.assert_consistent();
  489         -
            availability
  490         -
        };
  491         -
        Ok((availability, close_won))
  492         -
    }
  493         -
  494         -
    /// Completes local reuse state after a requesting cell accepts the sender.
  495         -
    pub(in crate::client::pool) fn complete_h1_reuse(
  496         -
        &self,
  497         -
        reuse_id: ReuseId,
  498         -
        transferred: bool,
  499         -
    ) -> H1AvailabilitySnapshot {
  500         -
        self.state.lock().finish_reuse(reuse_id, transferred)
  501         -
    }
  502         -
  503         -
    /// Publishes this cell's HTTP/1 availability when the origin is bounded.
  504         -
    fn publish_h1_availability(&self, availability: Option<H1AvailabilitySnapshot>) {
  505         -
        if let (Some(admission), Some(availability)) = (&self.admission, availability) {
  506         -
            OriginAdmission::update_h1_availability(
  507         -
                admission,
  508         -
                self.id.partition(),
  509         -
                self.eligibility_group.clone(),
  510         -
                availability,
  511         -
            );
  512         -
        }
  513         -
    }
  514         -
  515         -
    /// Returns a reusable sender to the oldest compatible waiter or idle set.
  516         -
    ///
  517         -
    /// Demand publication, task wakeup, and any rejected-result fallback all
  518         -
    /// run after the cell lock is released. `owner` remains outside the locked
  519         -
    /// scope so sender or connection drop cannot run while the cell guard is
  520         -
    /// live.
  521         -
    fn return_h1_owner(cell: &Arc<Self>, owner: OwnedH1) {
  522         -
        let connection_id = owner.id();
  523         -
        let mut owner = Some(owner);
  524         -
        let mut installation = None;
  525         -
        let mut intercepted = None;
  526         -
        let mut rejected_reuse = None;
  527         -
        let idle_deadline = cell.idle_deadline();
  528         -
        let should_retire = {
  529         -
            let mut state = cell.state.lock();
  530         -
            let returnable = state
  531         -
                .h1
  532         -
                .accepts_return(owner.as_ref().expect("HTTP/1 owner disappeared"));
  533         -
            if !returnable {
  534         -
                if let Some(reuse_id) = state.reuse.intercept_return() {
  535         -
                    let snapshot = state.finish_reuse(reuse_id, false);
  536         -
                    rejected_reuse = Some((reuse_id, snapshot));
  537         -
                } else {
  538         -
                    state.assert_consistent();
  539         -
                }
  540         -
                true
  541         -
            } else if let Some(reuse_id) = state.reuse.intercept_return() {
  542         -
                if state
  543         -
                    .h1
  544         -
                    .reserve_for_reuse(owner.as_ref().expect("HTTP/1 owner disappeared"))
  545         -
                {
  546         -
                    state.assert_consistent();
  547         -
                    intercepted = Some((
  548         -
                        reuse_id,
  549         -
                        ProvisionalH1::new(cell, owner.take().expect("HTTP/1 owner disappeared")),
  550         -
                    ));
  551         -
                    false
  552         -
                } else {
  553         -
                    let snapshot = state.finish_reuse(reuse_id, false);
  554         -
                    rejected_reuse = Some((reuse_id, snapshot));
  555         -
                    true
  556         -
                }
  557         -
            } else if state.waiters.can_accept_h1()
  558         -
                && state
  559         -
                    .h1
  560         -
                    .commit_return_to_waiter(owner.as_ref().expect("HTTP/1 owner disappeared"))
  561         -
            {
  562         -
                state.reuse.consume_local_turn();
  563         -
                state.assert_consistent();
  564         -
                let mut returned = owner.take().expect("HTTP/1 owner disappeared");
  565         -
                returned.mark_reused();
  566         -
                installation = Some(state.waiters.install_returned_h1(
  567         -
                    || AcquisitionResult::H1(H1Selection::new(cell, returned)),
  568         -
                    &cell.eligibility_group,
  569         -
                ));
  570         -
                false
  571         -
            } else {
  572         -
                let returned = state.h1.return_idle(
  573         -
                    owner.take().expect("HTTP/1 owner disappeared"),
  574         -
                    idle_deadline,
  575         -
                );
  576         -
                match returned {
  577         -
                    Ok(()) => {
  578         -
                        state.assert_consistent();
  579         -
                        false
  580         -
                    }
  581         -
                    Err(returned) => {
  582         -
                        owner = Some(returned);
  583         -
                        true
  584         -
                    }
  585         -
                }
  586         -
            }
  587         -
        };
  588         -
  589         -
        if should_retire {
  590         -
            if tracing::level_enabled!(tracing::Level::TRACE) {
  591         -
                trace_h1_return(cell, connection_id, H1ReturnTrace::Rejected);
  592         -
            }
  593         -
            if let Some((reuse_id, snapshot)) = rejected_reuse {
  594         -
                let admission = cell
  595         -
                    .admission
  596         -
                    .as_ref()
  597         -
                    .expect("an HTTP/1 reuse operation requires bounded admission");
  598         -
                OriginAdmission::reject_returned_h1_reuse(
  599         -
                    admission,
  600         -
                    reuse_id,
  601         -
                    cell.id.partition(),
  602         -
                    snapshot,
  603         -
                );
  604         -
            }
  605         -
            Self::retire_h1_owner(
  606         -
                cell,
  607         -
                owner.take().expect("retired HTTP/1 owner disappeared"),
  608         -
                CloseReason::ProtocolClosed,
  609         -
            );
  610         -
            return;
  611         -
        }
  612         -
  613         -
        if let Some((reuse_id, provisional)) = intercepted {
  614         -
            if tracing::level_enabled!(tracing::Level::TRACE) {
  615         -
                trace_h1_return(cell, connection_id, H1ReturnTrace::ReuseIntercepted);
  616         -
            }
  617         -
            let admission = cell
  618         -
                .admission
  619         -
                .as_ref()
  620         -
                .expect("an HTTP/1 reuse operation requires bounded admission");
  621         -
            let candidate = ReuseCandidate::new(
  622         -
                admission.clone(),
  623         -
                reuse_id,
  624         -
                cell.id.partition(),
  625         -
                provisional,
  626         -
            );
  627         -
            let action = OriginAdmission::resolve_h1_reuse(admission, reuse_id, candidate);
  628         -
            OriginAdmission::drive(action);
  629         -
            return;
  630         -
        }
  631         -
  632         -
        let Some(installation) = installation else {
  633         -
            if tracing::level_enabled!(tracing::Level::TRACE) {
  634         -
                trace_h1_return(cell, connection_id, H1ReturnTrace::Idle);
  635         -
            }
  636         -
            cell.notify_maintenance(idle_deadline);
  637         -
            if cell.admission.is_some() {
  638         -
                let availability = cell.state.lock().take_h1_availability_update();
  639         -
                cell.publish_h1_availability(availability);
  640         -
            }
  641         -
            return;
  642         -
        };
  643         -
        if tracing::level_enabled!(tracing::Level::TRACE) {
  644         -
            trace_h1_return(cell, connection_id, H1ReturnTrace::LocalDemand);
  645         -
        }
  646         -
        if let Some(admission) = &cell.admission {
  647         -
            for snapshot in installation.demand_updates.into_iter().flatten() {
  648         -
                OriginAdmission::publish_demand(admission, cell.id.partition(), snapshot);
  649         -
            }
  650         -
        }
  651         -
        drop(installation.returned_event);
  652         -
        if let Some(waker) = installation.waker {
  653         -
            waker.wake();
  654         -
        }
  655         -
        if cell.admission.is_some() {
  656         -
            let availability = cell.state.lock().take_h1_availability_update();
  657         -
            cell.publish_h1_availability(availability);
  658         -
        }
  659         -
    }
  660         -
  661         -
    /// Retires an externally owned H1 sender and removes its connection-owning cell record.
  662         -
    ///
  663         -
    /// Returns whether this path won the connection's logical-close race.
  664         -
    fn retire_h1_owner(cell: &Arc<Self>, owner: OwnedH1, reason: CloseReason) -> bool {
  665         -
        let should_close = {
  666         -
            let mut state = cell.state.lock();
  667         -
            let should_close = state.h1.close_owned(&owner);
  668         -
            state.assert_consistent();
  669         -
            should_close
  670         -
        };
  671         -
  672         -
        let id = owner.id();
  673         -
        let won = should_close && owner.connection().logical_close(reason);
  674         -
        drop(owner);
  675         -
  676         -
        let mut state = cell.state.lock();
  677         -
        state.h1.finish_close(id);
  678         -
        state.assert_consistent();
  679         -
        let availability = state.take_h1_availability_update();
  680         -
        drop(state);
  681         -
        cell.publish_h1_availability(availability);
  682         -
        won
  683         -
    }
  684         -
  685         -
    /// Begins close for an installed H1 generation named without its sender.
  686         -
    ///
  687         -
    /// Returns whether this signal won the connection's logical-close race.
  688         -
    fn close_h1(cell: &Arc<Self>, id: ConnectionId, reason: CloseReason) -> bool {
  689         -
        let Some((close, availability)) = ({
  690         -
            let mut state = cell.state.lock();
  691         -
            let close = state.h1.begin_close(id);
  692         -
            state.assert_consistent();
  693         -
            close.map(|close| (close, state.take_h1_availability_update()))
  694         -
        }) else {
  695         -
            return false;
  696         -
        };
  697         -
  698         -
        cell.publish_h1_availability(availability);
  699         -
        let remove_record = close.sender.is_some();
  700         -
        let won = close.connection.logical_close(reason);
  701         -
        drop(close.sender);
  702         -
        if remove_record {
  703         -
            let mut state = cell.state.lock();
  704         -
            state.h1.finish_close(id);
  705         -
            state.assert_consistent();
  706         -
        }
  707         -
        won
  708         -
    }
  709         -
  710         -
    /// Closes idle records whose maintenance deadline has elapsed.
         413  +
    /// Closes H1 records and H2 generations whose idle deadline elapsed.
  711    414   
    pub(super) fn expire_idle(cell: &Arc<Self>, now: SystemTime) {
  712         -
        let expired = cell.state.lock().h1.expired_idle(now);
  713         -
        for id in expired {
         415  +
        let (expired_h1, expired_h2) = {
         416  +
            let state = cell.state.lock();
         417  +
            (state.h1.expired_idle(now), state.h2.expired(now))
         418  +
        };
         419  +
        for id in expired_h1 {
  714    420   
            if Self::close_h1(cell, id, CloseReason::IdleTimeout) {
  715    421   
                tracing::trace!(
  716    422   
                    connection_id = %id,
  717    423   
                    connection_partition = ?cell.id.partition(),
  718    424   
                    origin_scheme = %cell.id.origin().scheme(),
  719    425   
                    origin_host = cell.id.origin().host(),
  720    426   
                    origin_port = ?cell.id.origin().port(),
  721    427   
                    "HTTP/1 idle connection expired"
  722    428   
                );
  723    429   
            }
  724    430   
        }
         431  +
        if let Some(generation) = expired_h2 {
         432  +
            if Self::close_h2(cell, generation, CloseReason::IdleTimeout) {
         433  +
                tracing::trace!(
         434  +
                    connection_partition = ?cell.id.partition(),
         435  +
                    origin_scheme = %cell.id.origin().scheme(),
         436  +
                    origin_host = cell.id.origin().host(),
         437  +
                    origin_port = ?cell.id.origin().port(),
         438  +
                    h2_generation = ?generation,
         439  +
                    "HTTP/2 idle generation expired"
         440  +
                );
         441  +
            }
         442  +
        }
  725    443   
    }
  726    444   
  727         -
    /// Returns this cell's nearest reusable H1 deadline.
         445  +
    /// Returns this cell's nearest reusable connection deadline.
  728    446   
    pub(super) fn nearest_idle_deadline(&self) -> Option<SystemTime> {
  729         -
        self.state.lock().h1.nearest_idle_deadline()
         447  +
        let state = self.state.lock();
         448  +
        [
         449  +
            state.h1.nearest_idle_deadline(),
         450  +
            state.h2.nearest_idle_deadline(),
         451  +
        ]
         452  +
        .into_iter()
         453  +
        .flatten()
         454  +
        .min()
  730    455   
    }
  731    456   
  732         -
    /// Logically closes every retained H1 record for pool shutdown.
  733         -
    pub(super) fn close_all_h1(cell: &Arc<Self>, reason: CloseReason) {
  734         -
        let ids = cell.state.lock().h1.connection_ids();
  735         -
        for id in ids {
         457  +
    /// Logically closes every retained connection for pool shutdown.
         458  +
    pub(super) fn close_all(cell: &Arc<Self>, reason: CloseReason) {
         459  +
        let (h1, h2) = {
         460  +
            let state = cell.state.lock();
         461  +
            (state.h1.connection_ids(), state.h2.generation_ids())
         462  +
        };
         463  +
        for id in h1 {
  736    464   
            Self::close_h1(cell, id, reason);
  737    465   
        }
         466  +
        for generation in h2 {
         467  +
            Self::close_h2(cell, generation, reason);
         468  +
        }
  738    469   
    }
  739    470   
  740    471   
    /// Applies one materialized acquisition delivery after admission unlock.
  741    472   
    ///
  742    473   
    /// Connection-cell H1 revalidation has already completed, so reserving
  743    474   
    /// the requesting cell cannot be followed by another fallible connection-
  744    475   
    /// cell transition.
  745    476   
    ///
  746    477   
    /// # Panics
  747    478   
    ///
  748    479   
    /// Panics if a waiter reserved by this function disappears or enters a
  749    480   
    /// state that cannot accept the committed acquisition event.
  750    481   
    pub(in crate::client::pool) fn receive_delivery(
  751    482   
        cell: &Arc<Self>,
  752    483   
        delivery: DeliveryGuard,
  753    484   
    ) -> Option<AdmissionAction> {
  754    485   
        let reservation = {
  755    486   
            let mut state = cell.state.lock();
  756    487   
            state
  757    488   
                .waiters
  758    489   
                .reserve_delivery_waiter(delivery.demand(), &cell.eligibility_group)
  759    490   
        };
  760    491   
  761    492   
        let DeliveryReservation::Reserved { waiter, successor } = reservation else {
  762    493   
            return delivery.reject(None);
  763    494   
        };
  764    495   
  765         -
        let (event, acknowledgement) = delivery.commit(successor);
  766         -
        let installation = {
         496  +
        let (event, mut acknowledgement) = delivery.commit(successor);
         497  +
        let (installation, suppress_successor) = {
  767    498   
            let mut state = cell.state.lock();
  768         -
            match event {
         499  +
            let installation = match event {
  769    500   
                AcquisitionEvent::Establish(permit) => {
  770    501   
                    state.waiters.install_capacity(waiter, permit)
  771    502   
                }
  772    503   
                AcquisitionEvent::Complete(result) => {
  773    504   
                    state.waiters.install_borrowed_h1(waiter, result)
  774    505   
                }
  775         -
            }
  776    506   
            };
         507  +
            (installation, state.h2.has_visible_h2())
         508  +
        };
         509  +
        if suppress_successor {
         510  +
            acknowledgement.suppress_h2_successor();
         511  +
        }
  777    512   
  778    513   
        let accepted = installation.accepted;
  779    514   
        let error = installation.error;
  780    515   
        let waker = installation.waker;
  781    516   
        let next = if accepted {
  782    517   
            drop(installation.returned_events);
  783    518   
            acknowledgement.accept()
  784    519   
        } else {
  785    520   
            acknowledgement.reject(installation.returned_events)
  786    521   
        };
  787    522   
        if let Some(waker) = waker {
  788    523   
            waker.wake();
  789    524   
        }
  790    525   
        if let Some(error) = error {
  791    526   
            match error {
  792    527   
                ResultInstallError::MissingWaiter => {
  793    528   
                    panic!("reserved waiter disappeared before acquisition delivery")
  794    529   
                }
  795    530   
                ResultInstallError::UnexpectedState => {
  796    531   
                    panic!("reserved waiter entered an invalid acquisition-delivery state")
  797    532   
                }
  798    533   
            }
  799    534   
        }
  800    535   
        next
  801    536   
    }
  802    537   
  803    538   
    /// Returns the number of retained acquisition waiters for boundary tests.
  804         -
    #[cfg(all(test, feature = "rt-tokio"))]
         539  +
    #[cfg(test)]
  805    540   
    pub(super) fn retained_waiters_for_test(&self) -> usize {
  806    541   
        self.state.lock().waiters.snapshot().retained
  807    542   
    }
  808    543   
  809         -
    /// Returns H1 record counts for focused ownership tests.
  810         -
    #[cfg(test)]
  811         -
    fn h1_counts(&self) -> (usize, usize) {
  812         -
        self.state.lock().h1.counts()
  813         -
    }
  814         -
  815         -
    /// Returns the sole installed HTTP/1 connection for focused dispatch tests.
  816         -
    #[cfg(all(test, feature = "rt-tokio"))]
  817         -
    pub(super) fn only_h1_connection_for_test(&self) -> Arc<ConnectionState> {
  818         -
        self.state.lock().h1.only_connection_for_test()
  819         -
    }
  820         -
  821    544   
    /// Registers one acquisition waiter in cell-local arrival order.
  822    545   
    ///
  823    546   
    /// The waiter and its demand snapshot are committed under the cell lock.
  824    547   
    /// A bounded cell publishes the snapshot to origin admission only after
  825    548   
    /// that lock is released. An unbounded cell retains only local order.
  826         -
    pub(super) fn register_waiter(&self, requirement: ProtocolRequirement) -> WaiterId {
  827         -
        let (waiter, snapshot) = {
  828         -
            let mut state = self.state.lock();
  829         -
            state.waiters.register_waiter(
         549  +
    pub(super) fn register_waiter(cell: &Arc<Self>, requirement: ProtocolRequirement) -> WaiterId {
         550  +
        let (waiter, snapshot, h2_visible) = {
         551  +
            let mut state = cell.state.lock();
         552  +
            let (waiter, snapshot) = state.waiters.register_waiter(
  830    553   
                requirement,
  831         -
                &self.eligibility_group,
  832         -
                self.admission.is_some(),
         554  +
                &cell.eligibility_group,
         555  +
                cell.admission.is_some(),
         556  +
            );
         557  +
            (
         558  +
                waiter,
         559  +
                snapshot,
         560  +
                state.h2.has_visible_h2() && requirement.accepts_h2(),
  833    561   
            )
  834    562   
        };
  835    563   
  836         -
        if let (Some(admission), Some(snapshot)) = (&self.admission, snapshot) {
  837         -
            OriginAdmission::publish_demand(admission, self.id.partition(), snapshot);
         564  +
        if let (Some(admission), Some(snapshot), false) = (&cell.admission, snapshot, h2_visible) {
         565  +
            OriginAdmission::publish_demand(admission, cell.id.partition(), snapshot);
  838    566   
        }
         567  +
        Self::service_h2_waiters(cell);
         568  +
        Self::service_peer_h2_waiters(cell);
  839    569   
        waiter
  840    570   
    }
  841    571   
  842    572   
    /// Cancels a waiter and re-examines local idle H1 state atomically.
  843    573   
    ///
  844    574   
    /// A newly compatible successor may be serviceable by an H1 that an older
  845    575   
    /// HTTP/2-only head could not use. The local sender is selected under the
  846    576   
    /// same cell lock as cancellation, so it never needs a same-cell peer
  847    577   
    /// reuse operation. Demand publication, fallback, and waking remain outside the lock.
  848    578   
    pub(super) fn cancel_waiter(cell: &Arc<Self>, waiter: WaiterId) -> bool {
  849    579   
        let transition = {
  850    580   
            let mut state = cell.state.lock();
         581  +
            state.h2.cancel_flight_participant(waiter);
         582  +
            state.h2.cancel_peer_activation(waiter);
         583  +
            state.h2.cancel_pending_waiter(waiter);
  851    584   
            state
  852    585   
                .waiters
  853    586   
                .cancel_waiter(waiter, &cell.eligibility_group)
  854         -
                .map(|cancelled| {
  855         -
                    let local_install = if state.waiters.can_accept_h1() {
         587  +
                .map(|mut cancelled| {
         588  +
                    let mut local_install = if state.waiters.can_accept_h1() {
  856    589   
                        state.h1.select_idle().map(|owner| {
  857    590   
                            state.reuse.consume_local_turn();
  858    591   
                            state.waiters.install_returned_h1(
  859    592   
                                || AcquisitionResult::H1(H1Selection::new(cell, owner)),
  860    593   
                                &cell.eligibility_group,
  861    594   
                            )
  862    595   
                        })
  863    596   
                    } else {
  864    597   
                        None
  865    598   
                    };
         599  +
                    cancelled.demand_updates =
         600  +
                        state.publishable_demand_updates(cancelled.demand_updates);
         601  +
                    if let Some(install) = &mut local_install {
         602  +
                        if let Some(waiter) = install.waiter {
         603  +
                            state.h2.cancel_pending_waiter(waiter);
         604  +
                        }
         605  +
                        install.demand_updates = state.publishable_demand_updates(std::mem::take(
         606  +
                            &mut install.demand_updates,
         607  +
                        ));
         608  +
                    }
  866    609   
                    (cancelled, local_install)
  867    610   
                })
  868    611   
        };
  869    612   
        let Some((cancelled, local_install)) = transition else {
  870    613   
            return false;
  871    614   
        };
  872    615   
  873    616   
        if let Some(admission) = &cell.admission {
  874    617   
            for snapshot in cancelled
  875    618   
                .demand_updates
  876    619   
                .into_iter()
  877    620   
                .chain(
  878    621   
                    local_install
  879    622   
                        .as_ref()
  880    623   
                        .into_iter()
  881    624   
                        .flat_map(|install| install.demand_updates.iter().cloned()),
  882    625   
                )
  883    626   
                .flatten()
  884    627   
            {
  885    628   
                OriginAdmission::publish_demand(admission, cell.id.partition(), snapshot);
  886    629   
            }
  887    630   
        }
  888    631   
  889    632   
        // Ready results and any locally rejected event cross the lock boundary
  890    633   
        // before their fallback can re-enter the pool.
  891    634   
        drop(cancelled.returned_events);
  892    635   
        if let Some(install) = local_install {
  893    636   
            drop(install.returned_event);
  894    637   
            if let Some(waker) = install.waker {
  895    638   
                waker.wake();
  896    639   
            }
  897    640   
        }
  898    641   
  899    642   
        let availability = {
  900    643   
            let mut state = cell.state.lock();
  901    644   
            let local_h1_demand = state.waiters.can_accept_h1();
  902    645   
            state.reuse.clear_unused_turn(local_h1_demand);
  903    646   
            state.assert_consistent();
  904    647   
            state.take_h1_availability_update()
  905    648   
        };
  906    649   
        cell.publish_h1_availability(availability);
         650  +
        Self::service_h2_waiters(cell);
         651  +
        Self::service_peer_h2_waiters(cell);
  907    652   
        true
  908    653   
    }
  909    654   
  910    655   
    /// Polls the next event for one acquisition waiter.
  911    656   
    ///
  912    657   
    /// # Panics
  913    658   
    ///
  914    659   
    /// Panics if `waiter` is unknown, was cancelled, or is polled again after
  915    660   
    /// its ready result was consumed.
  916    661   
    pub(super) fn poll_waiter(
  917    662   
        &self,
  918    663   
        waiter: WaiterId,
  919    664   
        cx: &mut Context<'_>,
  920    665   
    ) -> Poll<AcquisitionEvent> {
  921    666   
        let mut state = self.state.lock();
  922    667   
        state.waiters.poll_waiter(waiter, cx)
  923    668   
    }
  924    669   
  925    670   
    /// Marks an establishment attempt as started before its first connector poll.
  926    671   
    pub(super) fn start_establishment(&self, waiter: WaiterId) -> bool {
  927    672   
        self.state.lock().waiters.start_establishment(waiter)
  928    673   
    }
  929    674   
  930    675   
    /// Commits one terminal establishment result to its launching waiter.
  931    676   
    ///
  932    677   
    /// A returned H1 may already have served or cancelled the waiter. In that
  933    678   
    /// case the losing result leaves the cell lock and follows its ordinary
  934    679   
    /// sender-return or error-drop fallback.
  935    680   
    ///
  936    681   
    /// # Panics
  937    682   
    ///
  938    683   
    /// Panics if the launching waiter disappeared or left the launching state
  939    684   
    /// before its owned establishment completed.
  940    685   
    pub(super) fn complete_establishment(&self, waiter: WaiterId, result: AcquisitionResult) {
  941    686   
        let served_with_h1 = matches!(&result, AcquisitionResult::H1(_));
  942    687   
        let installation = {
  943    688   
            let mut state = self.state.lock();
  944    689   
            let installation = state.waiters.install_establishment_result(waiter, result);
         690  +
            let served_with_h1 = served_with_h1
         691  +
                && !installation.returned_events.iter().any(|event| {
         692  +
                    matches!(
         693  +
                        event,
         694  +
                        Some(AcquisitionEvent::Complete(AcquisitionResult::H1(_)))
         695  +
                    )
         696  +
                });
  945    697   
            if installation.accepted {
  946    698   
                if served_with_h1 {
  947    699   
                    state.reuse.consume_local_turn();
  948    700   
                } else {
  949    701   
                    let local_h1_demand = state.waiters.can_accept_h1();
  950    702   
                    state.reuse.clear_unused_turn(local_h1_demand);
  951    703   
                }
  952    704   
                state.assert_consistent();
  953    705   
            }
  954    706   
            installation
  955    707   
        };
  956    708   
        drop(installation.returned_events);
  957    709   
        if let Some(waker) = installation.waker {
  958    710   
            waker.wake();
  959    711   
        }
  960    712   
        if let Some(error) = installation.error {
  961    713   
            match error {
  962    714   
                ResultInstallError::MissingWaiter => {
  963    715   
                    unreachable!("establishment result reported a missing waiter")
  964    716   
                }
  965    717   
                ResultInstallError::UnexpectedState => {
  966    718   
                    panic!("establishment completed for a waiter that was not launching")
  967    719   
                }
  968    720   
            }
  969    721   
        }
  970    722   
        let availability = {
  971    723   
            let mut state = self.state.lock();
  972    724   
            state.assert_consistent();
  973    725   
            state.take_h1_availability_update()
  974    726   
        };
  975    727   
        self.publish_h1_availability(availability);
  976    728   
    }
  977    729   
  978    730   
    #[cfg(test)]
  979    731   
    pub(super) fn take_ready_lease(cell: &Arc<Self>, waiter: WaiterId) -> Option<CapacityLease> {
  980    732   
        let permit = match cell.take_ready_event(waiter)? {
  981    733   
            AcquisitionEvent::Establish(permit) => permit,
  982    734   
            AcquisitionEvent::Complete(_) => {
  983    735   
                panic!("capacity test received a terminal acquisition result")
  984    736   
            }
  985    737   
        };
  986    738   
        assert!(Self::cancel_waiter(cell, waiter));
  987    739   
        permit.into_lease()
  988    740   
    }
  989    741   
  990    742   
    #[cfg(test)]
  991    743   
    fn take_ready_h1(&self, waiter: WaiterId) -> Option<H1Selection> {
  992    744   
        match self.take_ready_event(waiter)? {
  993    745   
            AcquisitionEvent::Complete(AcquisitionResult::H1(selection)) => Some(selection),
         746  +
            AcquisitionEvent::Complete(AcquisitionResult::H2(_)) => {
         747  +
                panic!("HTTP/1 ownership test received an HTTP/2 activation")
         748  +
            }
  994    749   
            AcquisitionEvent::Complete(AcquisitionResult::Failed(_)) => {
  995    750   
                panic!("HTTP/1 ownership test received establishment failure")
  996    751   
            }
         752  +
            AcquisitionEvent::Complete(AcquisitionResult::Reacquire) => {
         753  +
                panic!("HTTP/1 ownership test received an internal reacquisition")
         754  +
            }
  997    755   
            AcquisitionEvent::Establish(_) => {
  998    756   
                panic!("HTTP/1 ownership test received establishment capacity")
  999    757   
            }
 1000    758   
        }
 1001    759   
    }
 1002    760   
 1003    761   
    #[cfg(test)]
 1004    762   
    fn take_ready_event(&self, waiter: WaiterId) -> Option<AcquisitionEvent> {
 1005    763   
        let mut state = self.state.lock();
 1006    764   
        match state
 1007    765   
            .waiters
 1008    766   
            .poll_waiter(waiter, &mut Context::from_waker(std::task::Waker::noop()))
 1009    767   
        {
 1010    768   
            Poll::Ready(event) => Some(event),
 1011    769   
            Poll::Pending => None,
 1012    770   
        }
 1013    771   
    }
 1014    772   
 1015    773   
    #[cfg(test)]
 1016    774   
    pub(super) fn register_waiter_without_publish(
 1017    775   
        &self,
 1018    776   
        requirement: ProtocolRequirement,
 1019    777   
    ) -> (WaiterId, DemandSnapshot) {
 1020    778   
        let (waiter, snapshot) =
 1021    779   
            self.state
 1022    780   
                .lock()
 1023    781   
                .waiters
 1024    782   
                .register_waiter(requirement, &self.eligibility_group, true);
 1025    783   
        (
 1026    784   
            waiter,
 1027    785   
            snapshot.expect("first unpublished waiter did not create demand"),
 1028    786   
        )
 1029    787   
    }
 1030    788   
 1031    789   
    #[cfg(test)]
 1032    790   
    fn snapshot(&self) -> CellSnapshot {
 1033    791   
        self.state.lock().waiters.snapshot()
 1034    792   
    }
 1035    793   
}
 1036    794   
 1037         -
/// Terminal outcome for one reusable HTTP/1 sender return.
 1038         -
enum H1ReturnTrace {
 1039         -
    /// The owning cell no longer accepts the sender.
 1040         -
    Rejected,
 1041         -
    /// Origin admission reserved the sender for peer demand.
 1042         -
    ReuseIntercepted,
 1043         -
    /// No compatible demand exists, so the sender became idle.
 1044         -
    Idle,
 1045         -
    /// A waiter in the owning cell accepted the sender.
 1046         -
    LocalDemand,
 1047         -
}
 1048         -
 1049         -
/// Emits a committed HTTP/1 return outcome outside the cell lock.
 1050         -
// Keep field formatting out of a return transition that can synchronously
 1051         -
// enter admission and sender fallbacks.
 1052         -
#[inline(never)]
 1053         -
fn trace_h1_return(cell: &OriginCell, connection_id: ConnectionId, outcome: H1ReturnTrace) {
 1054         -
    match outcome {
 1055         -
        H1ReturnTrace::Rejected => tracing::trace!(
 1056         -
            connection_id = %connection_id,
 1057         -
            connection_partition = ?cell.id.partition(),
 1058         -
            origin_scheme = %cell.id.origin().scheme(),
 1059         -
            origin_host = cell.id.origin().host(),
 1060         -
            origin_port = ?cell.id.origin().port(),
 1061         -
            "HTTP/1 return was rejected by its connection-owning cell"
 1062         -
        ),
 1063         -
        H1ReturnTrace::ReuseIntercepted => tracing::trace!(
 1064         -
            connection_id = %connection_id,
 1065         -
            connection_partition = ?cell.id.partition(),
 1066         -
            origin_scheme = %cell.id.origin().scheme(),
 1067         -
            origin_host = cell.id.origin().host(),
 1068         -
            origin_port = ?cell.id.origin().port(),
 1069         -
            "HTTP/1 return was intercepted by a cross-cell reuse operation"
 1070         -
        ),
 1071         -
        H1ReturnTrace::Idle => tracing::trace!(
 1072         -
            connection_id = %connection_id,
 1073         -
            connection_partition = ?cell.id.partition(),
 1074         -
            origin_scheme = %cell.id.origin().scheme(),
 1075         -
            origin_host = cell.id.origin().host(),
 1076         -
            origin_port = ?cell.id.origin().port(),
 1077         -
            "HTTP/1 connection returned to idle storage"
 1078         -
        ),
 1079         -
        H1ReturnTrace::LocalDemand => tracing::trace!(
 1080         -
            connection_id = %connection_id,
 1081         -
            request_partition = ?cell.id.partition(),
 1082         -
            connection_partition = ?cell.id.partition(),
 1083         -
            origin_scheme = %cell.id.origin().scheme(),
 1084         -
            origin_host = cell.id.origin().host(),
 1085         -
            origin_port = ?cell.id.origin().port(),
 1086         -
            "HTTP/1 return satisfied local demand"
 1087         -
        ),
 1088         -
    }
 1089         -
}
 1090         -
 1091    795   
impl std::fmt::Debug for OriginCell {
 1092    796   
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1093    797   
        f.debug_struct("OriginCell")
 1094    798   
            .field("id", &self.id)
 1095    799   
            .field("eligibility_group", &self.eligibility_group)
 1096    800   
            .field("admission", &self.admission)
 1097    801   
            .field("state", &self.state)
 1098    802   
            .finish()
 1099    803   
    }
 1100    804   
}
@@ -1276,980 +1812,1527 @@
 1296   1000   
            Some(CloseReason::IncompleteH1Exchange),
 1297   1001   
            connection.snapshot().close_reason
 1298   1002   
        );
 1299   1003   
    }
 1300   1004   
 1301   1005   
    #[test]
 1302   1006   
    fn returned_h1_satisfies_an_unbounded_waiter() {
 1303   1007   
        let cell = unbounded_cell();
 1304   1008   
        let (connection, _physical) = unbounded_connection(1);
 1305   1009   
        let selection = OriginCell::install_selected_h1(&cell, connection, H1Sender::test(11));
 1306         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1010  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1307   1011   
 1308   1012   
        drop(selection);
 1309   1013   
 1310   1014   
        let selected = cell
 1311   1015   
            .take_ready_h1(waiter)
 1312   1016   
            .expect("returned sender did not satisfy the waiter");
 1313   1017   
        assert_eq!(11, selected.test_sender_id());
 1314   1018   
        assert!(selected.is_reused());
 1315   1019   
        assert_eq!(0, cell.snapshot().retained);
 1316   1020   
        drop(selected);
 1317   1021   
        assert_eq!((1, 1), cell.h1_counts());
 1318   1022   
    }
 1319   1023   
 1320   1024   
    #[test]
 1321   1025   
    fn returned_h1_satisfies_bounded_demand_without_releasing_capacity() {
 1322   1026   
        let (admission, cell) = bounded_cell();
 1323   1027   
        let lease = OriginAdmission::lease_for_test(&admission);
 1324   1028   
        let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
 1325   1029   
        let selection = OriginCell::install_selected_h1(&cell, connection, H1Sender::test(11));
 1326         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1030  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1327   1031   
        assert_eq!(1, admission.ordered_demand_count_for_test());
 1328   1032   
 1329   1033   
        drop(selection);
 1330   1034   
 1331   1035   
        assert_eq!(0, admission.ordered_demand_count_for_test());
 1332   1036   
        assert_eq!(0, admission.available_capacity_for_test());
 1333   1037   
        let selected = cell
 1334   1038   
            .take_ready_h1(waiter)
 1335   1039   
            .expect("returned sender did not satisfy bounded demand");
 1336   1040   
        drop(selected);
 1337   1041   
        assert_eq!((1, 1), cell.h1_counts());
 1338   1042   
    }
 1339   1043   
 1340   1044   
    #[test]
 1341   1045   
    fn eligible_peer_borrows_an_idle_h1_without_moving_capacity() {
 1342   1046   
        let (admission, connection_cell, requesting_cell) =
 1343   1047   
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
 1344   1048   
        let lease = OriginAdmission::lease_for_test(&admission);
 1345   1049   
        let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
 1346   1050   
        OriginCell::install_idle_h1(&connection_cell, connection, H1Sender::test(11));
 1347   1051   
 1348         -
        let waiter = requesting_cell.register_waiter(ProtocolRequirement::H1Compatible);
        1052  +
        let waiter =
        1053  +
            OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H1Compatible);
 1349   1054   
        let borrowed = requesting_cell
 1350   1055   
            .take_ready_h1(waiter)
 1351   1056   
            .expect("eligible peer did not receive the idle HTTP/1 sender");
 1352   1057   
 1353   1058   
        assert_eq!(11, borrowed.test_sender_id());
 1354   1059   
        assert_eq!(0, admission.available_capacity_for_test());
 1355   1060   
        assert_eq!((1, 0), connection_cell.h1_counts());
 1356   1061   
        drop(borrowed);
 1357   1062   
        assert_eq!((1, 1), connection_cell.h1_counts());
 1358   1063   
    }
 1359   1064   
 1360   1065   
    #[test]
 1361   1066   
    fn ineligible_peer_reclaims_h1_capacity_without_moving_the_sender() {
 1362   1067   
        let (admission, connection_cell, requesting_cell) = bounded_peer_cells(
 1363   1068   
            1,
 1364   1069   
            EligibilityGroup::Partition(PartitionId::from_index(1)),
 1365   1070   
            EligibilityGroup::Partition(PartitionId::from_index(2)),
 1366   1071   
        );
 1367   1072   
        let lease = OriginAdmission::lease_for_test(&admission);
 1368   1073   
        let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
 1369   1074   
        OriginCell::install_idle_h1(&connection_cell, connection.clone(), H1Sender::test(11));
 1370   1075   
 1371         -
        let waiter = requesting_cell.register_waiter(ProtocolRequirement::H1Compatible);
        1076  +
        let waiter =
        1077  +
            OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H1Compatible);
 1372   1078   
        let replacement = OriginCell::take_ready_lease(&requesting_cell, waiter)
 1373   1079   
            .expect("ineligible peer did not receive reclaimed capacity");
 1374   1080   
 1375   1081   
        assert_eq!(
 1376   1082   
            Some(CloseReason::Reclaimed),
 1377   1083   
            connection.snapshot().close_reason
 1378   1084   
        );
 1379   1085   
        assert_eq!((0, 0), connection_cell.h1_counts());
 1380   1086   
        assert_eq!(0, admission.available_capacity_for_test());
 1381   1087   
        drop(replacement);
 1382   1088   
        assert_eq!(1, admission.available_capacity_for_test());
 1383   1089   
    }
 1384   1090   
 1385   1091   
    #[test]
 1386   1092   
    fn installed_peer_reuse_intercepts_the_next_active_h1_return() {
 1387   1093   
        let (admission, connection_cell, requesting_cell) =
 1388   1094   
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
 1389   1095   
        let lease = OriginAdmission::lease_for_test(&admission);
 1390   1096   
        let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
 1391   1097   
        let selected =
 1392   1098   
            OriginCell::install_selected_h1(&connection_cell, connection, H1Sender::test(11));
 1393         -
        let waiter = requesting_cell.register_waiter(ProtocolRequirement::H1Compatible);
        1099  +
        let waiter =
        1100  +
            OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H1Compatible);
 1394   1101   
 1395   1102   
        drop(selected);
 1396   1103   
 1397   1104   
        let borrowed = requesting_cell
 1398   1105   
            .take_ready_h1(waiter)
 1399   1106   
            .expect("installed reuse operation did not intercept the active return");
 1400   1107   
        assert_eq!(11, borrowed.test_sender_id());
 1401   1108   
        drop(borrowed);
 1402   1109   
        assert_eq!((1, 1), connection_cell.h1_counts());
 1403   1110   
    }
 1404   1111   
 1405   1112   
    #[test]
 1406   1113   
    fn cancelling_requesting_cell_releases_connection_reservation() {
 1407   1114   
        let (admission, connection_cell, requesting_cell) =
 1408   1115   
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
 1409   1116   
        let lease = OriginAdmission::lease_for_test(&admission);
 1410   1117   
        let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
 1411   1118   
        let selected =
 1412   1119   
            OriginCell::install_selected_h1(&connection_cell, connection, H1Sender::test(11));
 1413         -
        let waiter = requesting_cell.register_waiter(ProtocolRequirement::H1Compatible);
        1120  +
        let waiter =
        1121  +
            OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H1Compatible);
 1414   1122   
 1415   1123   
        assert!(OriginCell::cancel_waiter(&requesting_cell, waiter));
 1416   1124   
        assert!(
 1417   1125   
            connection_cell.state.lock().reuse.is_available(),
 1418   1126   
            "requesting cell cancellation did not reconcile the installed connection-owning cell reuse operation"
 1419   1127   
        );
 1420   1128   
        drop(selected);
 1421   1129   
 1422   1130   
        assert_eq!((1, 1), connection_cell.h1_counts());
 1423   1131   
        assert_eq!(0, admission.ordered_demand_count_for_test());
 1424   1132   
    }
 1425   1133   
 1426   1134   
    #[test]
 1427   1135   
    fn cross_cell_borrow_owes_one_usable_turn_to_the_owning_cell() {
 1428   1136   
        let (admission, connection_cell, requesting_cell) =
 1429   1137   
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
 1430   1138   
        let lease = OriginAdmission::lease_for_test(&admission);
 1431   1139   
        let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
 1432   1140   
        let selected =
 1433   1141   
            OriginCell::install_selected_h1(&connection_cell, connection, H1Sender::test(11));
 1434   1142   
 1435         -
        let requesting_waiter = requesting_cell.register_waiter(ProtocolRequirement::H1Compatible);
 1436         -
        let local_waiter = connection_cell.register_waiter(ProtocolRequirement::H1Compatible);
        1143  +
        let requesting_waiter =
        1144  +
            OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H1Compatible);
        1145  +
        let local_waiter =
        1146  +
            OriginCell::register_waiter(&connection_cell, ProtocolRequirement::H1Compatible);
 1437   1147   
        drop(selected);
 1438   1148   
 1439   1149   
        let borrowed = requesting_cell
 1440   1150   
            .take_ready_h1(requesting_waiter)
 1441   1151   
            .expect("older peer demand did not receive the intercepted sender");
 1442   1152   
        assert!(connection_cell.state.lock().reuse.local_turn_owed());
 1443   1153   
        drop(borrowed);
 1444   1154   
 1445   1155   
        let local = connection_cell
 1446   1156   
            .take_ready_h1(local_waiter)
 1447   1157   
            .expect("connection-owning cell local demand did not receive its owed turn");
 1448   1158   
        assert!(!connection_cell.state.lock().reuse.local_turn_owed());
 1449   1159   
        drop(local);
 1450   1160   
        assert_eq!((1, 1), connection_cell.h1_counts());
 1451   1161   
    }
 1452   1162   
 1453   1163   
    #[test]
 1454   1164   
    fn cancelling_ready_h1_returns_it_after_unlock() {
 1455   1165   
        let cell = unbounded_cell();
 1456   1166   
        let (connection, _physical) = unbounded_connection(1);
 1457   1167   
        let selection = OriginCell::install_selected_h1(&cell, connection, H1Sender::test(11));
 1458         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1168  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1459   1169   
        drop(selection);
 1460   1170   
 1461   1171   
        assert!(OriginCell::cancel_waiter(&cell, waiter));
 1462   1172   
        assert_eq!((1, 1), cell.h1_counts());
 1463   1173   
        assert_eq!(
 1464   1174   
            11,
 1465   1175   
            OriginCell::select_h1(&cell)
 1466   1176   
                .expect("cancelled result did not return its sender")
 1467   1177   
                .test_sender_id()
 1468   1178   
        );
 1469   1179   
    }
 1470   1180   
 1471   1181   
    #[test]
 1472   1182   
    fn returned_h1_and_establishment_complete_one_acquisition_attempt() {
 1473   1183   
        let cell = unbounded_cell();
 1474         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1184  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1475   1185   
        let AcquisitionEvent::Establish(permit) = cell
 1476   1186   
            .take_ready_event(waiter)
 1477   1187   
            .expect("unbounded miss did not start establishment")
 1478   1188   
        else {
 1479   1189   
            panic!("unbounded miss completed before establishment started");
 1480   1190   
        };
 1481   1191   
        assert!(cell.start_establishment(waiter));
 1482   1192   
        assert!(permit.into_lease().is_none());
 1483   1193   
 1484   1194   
        let (returning_connection, _returning_physical) = unbounded_connection(1);
 1485   1195   
        let returning =
 1486   1196   
            OriginCell::install_selected_h1(&cell, returning_connection, H1Sender::test(11));
 1487   1197   
        let (fresh_connection, _fresh_physical) = unbounded_connection(2);
 1488   1198   
        let fresh = OriginCell::install_selected_h1(&cell, fresh_connection, H1Sender::test(22));
 1489   1199   
 1490   1200   
        drop(returning);
 1491   1201   
        cell.complete_establishment(waiter, AcquisitionResult::H1(fresh));
 1492   1202   
 1493   1203   
        assert_eq!((2, 1), cell.h1_counts());
 1494   1204   
        let winner = cell
 1495   1205   
            .take_ready_h1(waiter)
 1496   1206   
            .expect("acquisition attempt had no terminal H1");
 1497   1207   
        assert_eq!(11, winner.test_sender_id());
 1498   1208   
        drop(winner);
 1499   1209   
        assert_eq!((2, 2), cell.h1_counts());
 1500   1210   
    }
 1501   1211   
 1502   1212   
    #[test]
 1503   1213   
    fn bounded_attempt_remains_eligible_for_a_returned_h1() {
 1504   1214   
        let (admission, cell) = bounded_cell_with_limit(2);
 1505   1215   
        let installed_lease = OriginAdmission::lease_for_test(&admission);
 1506   1216   
        let (connection, _physical) = ConnectionState::bounded(connection_info(1), installed_lease);
 1507   1217   
        let returning = OriginCell::install_selected_h1(&cell, connection, H1Sender::test(11));
 1508   1218   
 1509         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1219  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1510   1220   
        let AcquisitionEvent::Establish(permit) = cell
 1511   1221   
            .take_ready_event(waiter)
 1512   1222   
            .expect("bounded miss received no capacity")
 1513   1223   
        else {
 1514   1224   
            panic!("bounded miss completed before establishment started");
 1515   1225   
        };
 1516   1226   
        let attempt_lease = permit
 1517   1227   
            .into_lease()
 1518   1228   
            .expect("bounded establishment carried no capacity");
 1519   1229   
        assert_eq!(0, admission.available_capacity_for_test());
 1520   1230   
 1521   1231   
        drop(returning);
 1522   1232   
        let selected = cell
 1523   1233   
            .take_ready_h1(waiter)
 1524   1234   
            .expect("returned H1 did not beat the pending establishment");
 1525   1235   
        drop(attempt_lease);
 1526   1236   
        assert_eq!(1, admission.available_capacity_for_test());
 1527   1237   
        drop(selected);
 1528   1238   
        assert_eq!((1, 1), cell.h1_counts());
 1529   1239   
    }
 1530   1240   
 1531   1241   
    #[test]
 1532   1242   
    fn older_launching_waiter_precedes_younger_capacity_waiter_for_returned_h1() {
 1533   1243   
        let (admission, cell) = bounded_cell_with_limit(2);
 1534   1244   
        let installed_lease = OriginAdmission::lease_for_test(&admission);
 1535   1245   
        let (connection, _physical) = ConnectionState::bounded(connection_info(1), installed_lease);
 1536   1246   
        let returning = OriginCell::install_selected_h1(&cell, connection, H1Sender::test(11));
 1537   1247   
 1538         -
        let older = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1248  +
        let older = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1539   1249   
        let AcquisitionEvent::Establish(permit) = cell
 1540   1250   
            .take_ready_event(older)
 1541   1251   
            .expect("older waiter received no establishment capacity")
 1542   1252   
        else {
 1543   1253   
            panic!("older waiter completed before establishment started");
 1544   1254   
        };
 1545   1255   
        let attempt_lease = permit
 1546   1256   
            .into_lease()
 1547   1257   
            .expect("bounded establishment carried no capacity");
 1548   1258   
 1549         -
        let younger = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1259  +
        let younger = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1550   1260   
        assert!(cell.take_ready_event(younger).is_none());
 1551   1261   
 1552   1262   
        drop(returning);
 1553   1263   
 1554   1264   
        let selected = cell
 1555   1265   
            .take_ready_h1(older)
 1556   1266   
            .expect("younger capacity waiter overtook the older launching waiter");
 1557   1267   
        assert_eq!(11, selected.test_sender_id());
 1558   1268   
        assert!(cell.take_ready_event(younger).is_none());
 1559   1269   
 1560   1270   
        assert!(OriginCell::cancel_waiter(&cell, younger));
 1561   1271   
        drop(attempt_lease);
 1562   1272   
        drop(selected);
 1563   1273   
        assert_eq!((1, 1), cell.h1_counts());
 1564   1274   
        assert_eq!(1, admission.available_capacity_for_test());
 1565   1275   
    }
 1566   1276   
 1567   1277   
    #[test]
 1568   1278   
    fn establishment_failure_is_a_terminal_acquisition_result() {
 1569   1279   
        let cell = unbounded_cell();
 1570         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1280  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1571   1281   
        let AcquisitionEvent::Establish(permit) = cell
 1572   1282   
            .take_ready_event(waiter)
 1573   1283   
            .expect("unbounded miss did not start establishment")
 1574   1284   
        else {
 1575   1285   
            panic!("unbounded miss completed before establishment started");
 1576   1286   
        };
 1577   1287   
        assert!(cell.start_establishment(waiter));
 1578   1288   
        drop(permit);
 1579   1289   
 1580   1290   
        cell.complete_establishment(
 1581   1291   
            waiter,
 1582   1292   
            AcquisitionResult::Failed(ConnectorError::io(
 1583   1293   
                std::io::Error::other("synthetic establishment failure").into(),
 1584   1294   
            )),
 1585   1295   
        );
 1586   1296   
 1587   1297   
        let AcquisitionEvent::Complete(AcquisitionResult::Failed(error)) = cell
 1588   1298   
            .take_ready_event(waiter)
 1589   1299   
            .expect("establishment failure was not delivered")
 1590   1300   
        else {
 1591   1301   
            panic!("establishment failure produced the wrong acquisition event");
 1592   1302   
        };
 1593   1303   
        assert!(error.is_io());
 1594   1304   
        assert_eq!(0, cell.snapshot().retained);
 1595   1305   
    }
 1596   1306   
 1597   1307   
    #[test]
 1598   1308   
    fn establishment_completion_clears_the_served_waiters_local_turn() {
 1599   1309   
        let cell = unbounded_cell();
 1600   1310   
        let reuse_id = ReuseId::for_test(1);
 1601   1311   
        {
 1602   1312   
            let mut state = cell.state.lock();
 1603   1313   
            assert!(state.reuse.install_resolving(reuse_id));
 1604   1314   
            assert!(state.reuse.complete_transfer(reuse_id, true));
 1605   1315   
        }
 1606         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1316  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1607   1317   
        let AcquisitionEvent::Establish(permit) = cell
 1608   1318   
            .take_ready_event(waiter)
 1609   1319   
            .expect("unbounded miss did not prepare establishment")
 1610   1320   
        else {
 1611   1321   
            panic!("unbounded miss completed before establishment was prepared");
 1612   1322   
        };
 1613   1323   
        assert!(cell.start_establishment(waiter));
 1614   1324   
        drop(permit);
 1615   1325   
        let (connection, _physical) = unbounded_connection(1);
 1616   1326   
        let fresh = OriginCell::install_selected_h1(&cell, connection, H1Sender::test(11));
 1617   1327   
 1618   1328   
        cell.complete_establishment(waiter, AcquisitionResult::H1(fresh));
 1619   1329   
 1620   1330   
        assert!(!cell.state.lock().reuse.local_turn_owed());
 1621   1331   
        drop(
 1622   1332   
            cell.take_ready_h1(waiter)
 1623   1333   
                .expect("successful establishment result was not retained"),
 1624   1334   
        );
 1625   1335   
    }
 1626   1336   
 1627   1337   
    #[test]
 1628   1338   
    fn failed_establishment_preserves_a_turn_for_compatible_successor() {
 1629   1339   
        let cell = unbounded_cell();
 1630   1340   
        let reuse_id = ReuseId::for_test(1);
 1631   1341   
        {
 1632   1342   
            let mut state = cell.state.lock();
 1633   1343   
            assert!(state.reuse.install_resolving(reuse_id));
 1634   1344   
            assert!(state.reuse.complete_transfer(reuse_id, true));
 1635   1345   
        }
 1636         -
        let failed = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1346  +
        let failed = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1637   1347   
        let AcquisitionEvent::Establish(permit) = cell
 1638   1348   
            .take_ready_event(failed)
 1639   1349   
            .expect("unbounded miss did not prepare establishment")
 1640   1350   
        else {
 1641   1351   
            panic!("unbounded miss completed before establishment was prepared");
 1642   1352   
        };
 1643   1353   
        assert!(cell.start_establishment(failed));
 1644   1354   
        drop(permit);
 1645         -
        let successor = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1355  +
        let successor = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1646   1356   
 1647   1357   
        cell.complete_establishment(
 1648   1358   
            failed,
 1649   1359   
            AcquisitionResult::Failed(ConnectorError::io(
 1650   1360   
                std::io::Error::other("synthetic establishment failure").into(),
 1651   1361   
            )),
 1652   1362   
        );
 1653   1363   
 1654   1364   
        assert!(cell.state.lock().reuse.local_turn_owed());
 1655   1365   
        assert!(matches!(
 1656   1366   
            cell.take_ready_event(failed),
 1657   1367   
            Some(AcquisitionEvent::Complete(AcquisitionResult::Failed(_)))
 1658   1368   
        ));
 1659   1369   
        assert!(OriginCell::cancel_waiter(&cell, successor));
 1660   1370   
        assert!(!cell.state.lock().reuse.local_turn_owed());
 1661   1371   
    }
 1662   1372   
 1663   1373   
    #[test]
 1664   1374   
    fn failed_establishment_clears_a_turn_after_local_demand_drains() {
 1665   1375   
        let cell = unbounded_cell();
 1666   1376   
        let reuse_id = ReuseId::for_test(1);
 1667   1377   
        {
 1668   1378   
            let mut state = cell.state.lock();
 1669   1379   
            assert!(state.reuse.install_resolving(reuse_id));
 1670   1380   
            assert!(state.reuse.complete_transfer(reuse_id, true));
 1671   1381   
        }
 1672         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1382  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1673   1383   
        let AcquisitionEvent::Establish(permit) = cell
 1674   1384   
            .take_ready_event(waiter)
 1675   1385   
            .expect("unbounded miss did not prepare establishment")
 1676   1386   
        else {
 1677   1387   
            panic!("unbounded miss completed before establishment was prepared");
 1678   1388   
        };
 1679   1389   
        assert!(cell.start_establishment(waiter));
 1680   1390   
        drop(permit);
 1681   1391   
 1682   1392   
        cell.complete_establishment(
 1683   1393   
            waiter,
 1684   1394   
            AcquisitionResult::Failed(ConnectorError::io(
 1685   1395   
                std::io::Error::other("synthetic establishment failure").into(),
 1686   1396   
            )),
 1687   1397   
        );
 1688   1398   
 1689   1399   
        assert!(!cell.state.lock().reuse.local_turn_owed());
 1690   1400   
        assert!(matches!(
 1691   1401   
            cell.take_ready_event(waiter),
 1692   1402   
            Some(AcquisitionEvent::Complete(AcquisitionResult::Failed(_)))
 1693   1403   
        ));
 1694   1404   
    }
 1695   1405   
 1696   1406   
    #[test]
 1697   1407   
    fn completion_after_waiter_cancellation_returns_the_new_h1() {
 1698   1408   
        let cell = unbounded_cell();
 1699         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1409  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1700   1410   
        let AcquisitionEvent::Establish(permit) = cell
 1701   1411   
            .take_ready_event(waiter)
 1702   1412   
            .expect("unbounded miss did not start establishment")
 1703   1413   
        else {
 1704   1414   
            panic!("unbounded miss completed before establishment started");
 1705   1415   
        };
 1706   1416   
        assert!(cell.start_establishment(waiter));
 1707   1417   
        assert!(OriginCell::cancel_waiter(&cell, waiter));
 1708   1418   
        drop(permit);
 1709   1419   
 1710   1420   
        let (connection, _physical) = unbounded_connection(1);
 1711   1421   
        let fresh = OriginCell::install_selected_h1(&cell, connection, H1Sender::test(11));
 1712   1422   
        cell.complete_establishment(waiter, AcquisitionResult::H1(fresh));
 1713   1423   
 1714   1424   
        assert_eq!((1, 1), cell.h1_counts());
 1715   1425   
        assert_eq!(
 1716   1426   
            11,
 1717   1427   
            OriginCell::select_h1(&cell)
 1718   1428   
                .expect("cancelled acquisition lost its completed H1")
 1719   1429   
                .test_sender_id()
 1720   1430   
        );
 1721   1431   
    }
 1722   1432   
 1723   1433   
    #[test]
 1724   1434   
    fn returned_h1_prevents_the_first_establishment_poll() {
 1725   1435   
        let cell = unbounded_cell();
 1726         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1436  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1727   1437   
        let AcquisitionEvent::Establish(permit) = cell
 1728   1438   
            .take_ready_event(waiter)
 1729   1439   
            .expect("unbounded miss did not prepare establishment")
 1730   1440   
        else {
 1731   1441   
            panic!("unbounded miss completed before establishment was prepared");
 1732   1442   
        };
 1733   1443   
        let (connection, _physical) = unbounded_connection(1);
 1734   1444   
        let returning = OriginCell::install_selected_h1(&cell, connection, H1Sender::test(11));
 1735   1445   
 1736   1446   
        drop(returning);
 1737   1447   
        assert!(!cell.start_establishment(waiter));
 1738   1448   
        drop(permit);
 1739   1449   
        let selected = cell
 1740   1450   
            .take_ready_h1(waiter)
 1741   1451   
            .expect("returned H1 did not win before establishment started");
 1742   1452   
        assert_eq!(11, selected.test_sender_id());
 1743   1453   
    }
 1744   1454   
 1745   1455   
    #[test]
 1746   1456   
    fn h2_required_head_does_not_take_h1() {
 1747   1457   
        let cell = unbounded_cell();
 1748   1458   
        let (connection, _physical) = unbounded_connection(1);
 1749   1459   
        let selection = OriginCell::install_selected_h1(&cell, connection, H1Sender::test(11));
 1750         -
        let waiter = cell.register_waiter(ProtocolRequirement::H2Required);
        1460  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H2Required);
 1751   1461   
 1752   1462   
        drop(selection);
 1753   1463   
 1754   1464   
        assert_eq!((1, 1), cell.h1_counts());
 1755   1465   
        let AcquisitionEvent::Establish(permit) = cell
 1756   1466   
            .take_ready_event(waiter)
 1757   1467   
            .expect("unbounded miss did not start establishment")
 1758   1468   
        else {
 1759   1469   
            panic!("H2-required waiter accepted an HTTP/1 selection");
 1760   1470   
        };
 1761   1471   
        assert!(OriginCell::cancel_waiter(&cell, waiter));
 1762   1472   
        drop(permit);
 1763   1473   
    }
 1764   1474   
 1765   1475   
    #[test]
 1766         -
    fn cancelling_h2_head_serves_compatible_successor_locally() {
        1476  +
    fn cancelling_h2_head_refunnels_reclaimed_capacity_to_successor() {
 1767   1477   
        let (admission, cell) = bounded_cell();
 1768   1478   
        let lease = OriginAdmission::lease_for_test(&admission);
 1769   1479   
        let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
 1770   1480   
        OriginCell::install_idle_h1(&cell, connection, H1Sender::test(11));
 1771         -
        let h2_head = cell.register_waiter(ProtocolRequirement::H2Required);
 1772         -
        let h1_successor = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1481  +
        let h2_head = OriginCell::register_waiter(&cell, ProtocolRequirement::H2Required);
        1482  +
        let h1_successor = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1773   1483   
 1774         -
        assert!(cell.take_ready_event(h2_head).is_none());
        1484  +
        let AcquisitionEvent::Establish(permit) = cell
        1485  +
            .take_ready_event(h2_head)
        1486  +
            .expect("HTTP/2 demand did not receive reclaimed local capacity")
        1487  +
        else {
        1488  +
            panic!("HTTP/2 demand received a protocol handle instead of capacity");
        1489  +
        };
 1775   1490   
        assert!(OriginCell::cancel_waiter(&cell, h2_head));
        1491  +
        drop(permit);
 1776   1492   
 1777         -
        let selected = cell
 1778         -
            .take_ready_h1(h1_successor)
 1779         -
            .expect("local idle H1 did not serve the compatible successor");
 1780         -
        assert_eq!(11, selected.test_sender_id());
        1493  +
        let successor = OriginCell::take_ready_lease(&cell, h1_successor)
        1494  +
            .expect("reclaimed capacity did not reach the compatible successor");
        1495  +
        assert_eq!((0, 0), cell.h1_counts());
 1781   1496   
        assert!(cell.state.lock().reuse.is_available());
 1782         -
        drop(selected);
        1497  +
        drop(successor);
 1783   1498   
    }
 1784   1499   
 1785   1500   
    #[test]
 1786   1501   
    fn close_marks_selected_record_until_sender_returns() {
 1787   1502   
        let cell = unbounded_cell();
 1788   1503   
        let (connection, _physical) = unbounded_connection(1);
 1789   1504   
        let selection =
 1790   1505   
            OriginCell::install_selected_h1(&cell, connection.clone(), H1Sender::test(11));
 1791   1506   
        let close = H1CloseHandle::new(&cell, selection.connection());
 1792   1507   
@@ -1848,1563 +1984,1699 @@
 1868   1583   
            Some(CloseReason::OwnerRuntimeShutdown),
 1869   1584   
            connection.snapshot().close_reason
 1870   1585   
        );
 1871   1586   
        drop(selection);
 1872   1587   
        assert_eq!((0, 0), cell.h1_counts());
 1873   1588   
    }
 1874   1589   
 1875   1590   
    #[test]
 1876   1591   
    fn three_waiters_receive_capacity_in_fifo_order() {
 1877   1592   
        let (_admission, cell) = bounded_cell();
 1878         -
        let first = cell.register_waiter(ProtocolRequirement::H1Compatible);
 1879         -
        let second = cell.register_waiter(ProtocolRequirement::H1Compatible);
 1880         -
        let third = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1593  +
        let first = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
        1594  +
        let second = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
        1595  +
        let third = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1881   1596   
 1882   1597   
        let first_lease = OriginCell::take_ready_lease(&cell, first).unwrap();
 1883   1598   
        assert!(OriginCell::take_ready_lease(&cell, second).is_none());
 1884   1599   
        assert!(OriginCell::take_ready_lease(&cell, third).is_none());
 1885   1600   
 1886   1601   
        drop(first_lease);
 1887   1602   
        let second_lease = OriginCell::take_ready_lease(&cell, second).unwrap();
 1888   1603   
        assert!(OriginCell::take_ready_lease(&cell, third).is_none());
 1889   1604   
 1890   1605   
        drop(second_lease);
 1891   1606   
        let third_lease = OriginCell::take_ready_lease(&cell, third).unwrap();
 1892   1607   
        drop(third_lease);
 1893   1608   
        assert_eq!(0, cell.snapshot().retained);
 1894   1609   
    }
 1895   1610   
 1896   1611   
    #[test]
 1897   1612   
    fn cancelling_middle_and_tail_waiters_repairs_fifo_links() {
 1898   1613   
        let (_admission, cell, held) = saturated_bounded_cell();
 1899         -
        let first = cell.register_waiter(ProtocolRequirement::H1Compatible);
 1900         -
        let second = cell.register_waiter(ProtocolRequirement::H2Required);
 1901         -
        let third = cell.register_waiter(ProtocolRequirement::H1Compatible);
 1902         -
        let fourth = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1614  +
        let first = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
        1615  +
        let second = OriginCell::register_waiter(&cell, ProtocolRequirement::H2Required);
        1616  +
        let third = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
        1617  +
        let fourth = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1903   1618   
        let demand = cell.snapshot().demand;
 1904   1619   
 1905   1620   
        assert!(OriginCell::cancel_waiter(&cell, second));
 1906   1621   
        assert!(OriginCell::cancel_waiter(&cell, fourth));
 1907   1622   
        assert_eq!(demand, cell.snapshot().demand);
 1908   1623   
        assert_eq!(2, cell.snapshot().waiting);
 1909         -
        let fifth = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1624  +
        let fifth = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1910   1625   
        assert_eq!(3, cell.snapshot().waiting);
 1911   1626   
 1912   1627   
        drop(held);
 1913   1628   
        let first_lease = OriginCell::take_ready_lease(&cell, first).unwrap();
 1914   1629   
        assert!(OriginCell::take_ready_lease(&cell, third).is_none());
 1915   1630   
        assert!(OriginCell::take_ready_lease(&cell, fifth).is_none());
 1916   1631   
        drop(first_lease);
 1917   1632   
 1918   1633   
        let third_lease = OriginCell::take_ready_lease(&cell, third).unwrap();
 1919   1634   
        assert!(OriginCell::take_ready_lease(&cell, fifth).is_none());
 1920   1635   
        drop(third_lease);
 1921   1636   
 1922   1637   
        drop(OriginCell::take_ready_lease(&cell, fifth).unwrap());
 1923   1638   
        assert_eq!(0, cell.snapshot().retained);
 1924   1639   
    }
 1925   1640   
 1926   1641   
    #[test]
 1927   1642   
    fn cancelling_head_waiter_preserves_remaining_fifo_order() {
 1928   1643   
        let (_admission, cell, held) = saturated_bounded_cell();
 1929         -
        let first = cell.register_waiter(ProtocolRequirement::H1Compatible);
 1930         -
        let second = cell.register_waiter(ProtocolRequirement::H1Compatible);
 1931         -
        let third = cell.register_waiter(ProtocolRequirement::H1Compatible);
 1932         -
        let fourth = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1644  +
        let first = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
        1645  +
        let second = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
        1646  +
        let third = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
        1647  +
        let fourth = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1933   1648   
 1934   1649   
        assert!(OriginCell::cancel_waiter(&cell, first));
 1935   1650   
        drop(held);
 1936   1651   
 1937   1652   
        let second_lease = OriginCell::take_ready_lease(&cell, second).unwrap();
 1938   1653   
        assert!(OriginCell::take_ready_lease(&cell, third).is_none());
 1939   1654   
        assert!(OriginCell::take_ready_lease(&cell, fourth).is_none());
 1940   1655   
        drop(second_lease);
 1941   1656   
 1942   1657   
        let third_lease = OriginCell::take_ready_lease(&cell, third).unwrap();
 1943   1658   
        assert!(OriginCell::take_ready_lease(&cell, fourth).is_none());
 1944   1659   
        drop(third_lease);
 1945   1660   
 1946   1661   
        drop(OriginCell::take_ready_lease(&cell, fourth).unwrap());
 1947   1662   
        assert_eq!(0, cell.snapshot().retained);
 1948   1663   
    }
 1949   1664   
 1950   1665   
    #[test]
 1951   1666   
    fn cancelling_ready_waiter_refunnels_capacity() {
 1952   1667   
        let (_admission, cell) = bounded_cell();
 1953         -
        let first = cell.register_waiter(ProtocolRequirement::H1Compatible);
 1954         -
        let second = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1668  +
        let first = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
        1669  +
        let second = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 1955   1670   
 1956   1671   
        assert!(OriginCell::cancel_waiter(&cell, first));
 1957   1672   
        let lease = OriginCell::take_ready_lease(&cell, second).unwrap();
 1958   1673   
        drop(lease);
 1959   1674   
    }
 1960   1675   
 1961   1676   
    #[test]
 1962   1677   
    fn cancelling_during_delivery_refunnels_capacity_after_unlock() {
 1963   1678   
        let (admission, cell) = bounded_cell();
 1964   1679   
        let (waiter, demand) =
@@ -2092,1807 +2152,1867 @@
 2112   1827   
                .expect("cancelled crossing lost its H1 sender")
 2113   1828   
                .test_sender_id()
 2114   1829   
        );
 2115   1830   
    }
 2116   1831   
 2117   1832   
    #[test]
 2118   1833   
    fn stale_delivery_is_rejected_after_head_cancellation() {
 2119   1834   
        let (admission, cell) = bounded_cell();
 2120   1835   
        let (first, first_demand) =
 2121   1836   
            cell.register_waiter_without_publish(ProtocolRequirement::H2Required);
 2122         -
        let second = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1837  +
        let second = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 2123   1838   
        let stale = OriginAdmission::publish_without_driving(
 2124   1839   
            &admission,
 2125   1840   
            cell.id().partition(),
 2126   1841   
            first_demand,
 2127   1842   
        )
 2128   1843   
        .expect("first demand did not reserve capacity");
 2129   1844   
 2130   1845   
        assert!(OriginCell::cancel_waiter(&cell, first));
 2131   1846   
        OriginAdmission::drive(Some(AdmissionAction::Delivery(stale)));
 2132   1847   
@@ -2172,1887 +2276,2289 @@
 2192   1907   
        OriginAdmission::drive(Some(next));
 2193   1908   
        drop(
 2194   1909   
            OriginCell::take_ready_lease(&target, target_waiter)
 2195   1910   
                .expect("existing driver did not deliver the successor"),
 2196   1911   
        );
 2197   1912   
    }
 2198   1913   
 2199   1914   
    #[test]
 2200   1915   
    fn cancelling_the_only_waiter_retires_admission_demand() {
 2201   1916   
        let (admission, cell, held) = saturated_bounded_cell();
 2202         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1917  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 2203   1918   
        assert_eq!(1, admission.ordered_demand_count_for_test());
 2204   1919   
 2205   1920   
        assert!(OriginCell::cancel_waiter(&cell, waiter));
 2206   1921   
        assert_eq!(0, admission.ordered_demand_count_for_test());
 2207   1922   
        drop(held);
 2208   1923   
    }
 2209   1924   
 2210   1925   
    #[test]
 2211   1926   
    fn unknown_waiter_cancellation_is_a_noop() {
 2212   1927   
        let (_admission, cell) = bounded_cell();
 2213   1928   
        assert!(!OriginCell::cancel_waiter(&cell, WaiterId(99)));
 2214   1929   
    }
 2215   1930   
 2216   1931   
    #[test]
 2217   1932   
    fn unbounded_waiter_registers_and_cancels_locally() {
 2218   1933   
        let cell = Arc::new(OriginCell::new(
 2219   1934   
            PartitionId::from_index(1),
 2220   1935   
            OriginKey::from_parts(Scheme::HTTPS, "example.com", None).unwrap(),
 2221   1936   
            EligibilityGroup::Pool,
 2222   1937   
            None,
 2223   1938   
            None,
 2224   1939   
        ));
 2225   1940   
 2226         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1941  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 2227   1942   
        assert_eq!(0, cell.snapshot().waiting);
 2228   1943   
        assert_eq!(1, cell.snapshot().retained);
 2229   1944   
        assert!(OriginCell::cancel_waiter(&cell, waiter));
 2230   1945   
        assert_eq!(0, cell.snapshot().retained);
 2231   1946   
    }
 2232   1947   
 2233   1948   
    #[test]
 2234   1949   
    fn delivered_waiter_is_woken_once() {
 2235   1950   
        let (_admission, cell, held) = saturated_bounded_cell();
 2236         -
        let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        1951  +
        let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 2237   1952   
        let counter = StdArc::new(WakeCounter(AtomicUsize::new(0)));
 2238   1953   
        let waker = Waker::from(counter.clone());
 2239   1954   
        let mut context = Context::from_waker(&waker);
 2240   1955   
        assert!(cell.poll_waiter(waiter, &mut context).is_pending());
 2241   1956   
 2242   1957   
        drop(held);
 2243   1958   
        assert_eq!(1, counter.0.load(Ordering::Relaxed));
 2244   1959   
        drop(OriginCell::take_ready_lease(&cell, waiter).expect("woken waiter had no capacity"));
 2245   1960   
        assert_eq!(1, counter.0.load(Ordering::Relaxed));
 2246   1961   
    }
        1962  +
        1963  +
    fn install_bounded_h2(
        1964  +
        admission: &Arc<OriginAdmission>,
        1965  +
        cell: &Arc<OriginCell>,
        1966  +
        connection_id: u64,
        1967  +
    ) -> (
        1968  +
        h2::H2GenerationId,
        1969  +
        Arc<ConnectionState>,
        1970  +
        super::super::connection::PhysicalConnectionGuard,
        1971  +
    ) {
        1972  +
        let lease = OriginAdmission::lease_for_test(admission);
        1973  +
        let (connection, physical) = ConnectionState::bounded(
        1974  +
            ConnectionInfo::for_test(ConnectionId::new(connection_id), cell.id().partition()),
        1975  +
            lease,
        1976  +
        );
        1977  +
        let generation =
        1978  +
            OriginCell::install_h2_for_test(cell, connection.clone(), connection_id, None);
        1979  +
        (generation, connection, physical)
        1980  +
    }
        1981  +
        1982  +
    fn take_ready_h2(cell: &OriginCell, waiter: WaiterId) -> h2::H2Activation {
        1983  +
        match cell
        1984  +
            .take_ready_event(waiter)
        1985  +
            .expect("HTTP/2 waiter did not receive an activation")
        1986  +
        {
        1987  +
            AcquisitionEvent::Complete(AcquisitionResult::H2(activation)) => activation,
        1988  +
            AcquisitionEvent::Establish(_) => {
        1989  +
                panic!("HTTP/2 waiter received establishment capacity")
        1990  +
            }
        1991  +
            AcquisitionEvent::Complete(AcquisitionResult::H1(_)) => {
        1992  +
                panic!("HTTP/2 waiter received an HTTP/1 sender")
        1993  +
            }
        1994  +
            AcquisitionEvent::Complete(AcquisitionResult::Reacquire) => {
        1995  +
                panic!("HTTP/2 waiter was returned for reacquisition")
        1996  +
            }
        1997  +
            AcquisitionEvent::Complete(AcquisitionResult::Failed(error)) => {
        1998  +
                panic!("HTTP/2 waiter received an establishment failure: {error}")
        1999  +
            }
        2000  +
        }
        2001  +
    }
        2002  +
        2003  +
    #[test]
        2004  +
    fn eligible_peer_h2_generation_satisfies_bounded_demand() {
        2005  +
        let (admission, connection_cell, requesting_cell) =
        2006  +
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
        2007  +
        let (generation, connection, _physical) =
        2008  +
            install_bounded_h2(&admission, &connection_cell, 1);
        2009  +
        2010  +
        let waiter = OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H2Required);
        2011  +
        let activation = take_ready_h2(&requesting_cell, waiter);
        2012  +
        2013  +
        assert_eq!(generation, activation.generation());
        2014  +
        assert!(Arc::ptr_eq(&connection, activation.connection()));
        2015  +
        assert_eq!(0, admission.available_capacity_for_test());
        2016  +
        assert_eq!(Some(generation), connection_cell.accepting_h2_generation());
        2017  +
        drop(activation);
        2018  +
        assert_eq!(0, requesting_cell.snapshot().retained);
        2019  +
        assert!(OriginCell::close_h2(
        2020  +
            &connection_cell,
        2021  +
            generation,
        2022  +
            CloseReason::PoolDropped,
        2023  +
        ));
        2024  +
        assert_eq!(1, admission.available_capacity_for_test());
        2025  +
    }
        2026  +
        2027  +
    #[test]
        2028  +
    fn peer_h2_publication_respects_eligibility_group() {
        2029  +
        let groups = [
        2030  +
            (
        2031  +
                EligibilityGroup::Partition(PartitionId::from_index(1)),
        2032  +
                EligibilityGroup::Partition(PartitionId::from_index(2)),
        2033  +
            ),
        2034  +
            (
        2035  +
                EligibilityGroup::NetworkInterface(Some(Arc::from("eth0"))),
        2036  +
                EligibilityGroup::NetworkInterface(Some(Arc::from("eth1"))),
        2037  +
            ),
        2038  +
        ];
        2039  +
        for (connection_group, requesting_group) in groups {
        2040  +
            let (admission, connection_cell, requesting_cell) =
        2041  +
                bounded_peer_cells(1, connection_group, requesting_group);
        2042  +
            let (generation, _connection, _physical) =
        2043  +
                install_bounded_h2(&admission, &connection_cell, 1);
        2044  +
            let waiter =
        2045  +
                OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H2Required);
        2046  +
        2047  +
            assert!(requesting_cell.take_ready_event(waiter).is_none());
        2048  +
            assert_eq!(1, admission.ordered_demand_count_for_test());
        2049  +
            assert!(OriginCell::cancel_waiter(&requesting_cell, waiter));
        2050  +
            assert!(OriginCell::close_h2(
        2051  +
                &connection_cell,
        2052  +
                generation,
        2053  +
                CloseReason::PoolDropped,
        2054  +
            ));
        2055  +
            assert_eq!(1, admission.available_capacity_for_test());
        2056  +
        }
        2057  +
    }
        2058  +
        2059  +
    #[test]
        2060  +
    fn dropped_publication_guard_retries_the_same_demand() {
        2061  +
        let (admission, connection_cell, requesting_cell) =
        2062  +
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
        2063  +
        let (generation, _connection, _physical) =
        2064  +
            install_bounded_h2(&admission, &connection_cell, 1);
        2065  +
        let (waiter, demand) =
        2066  +
            requesting_cell.register_waiter_without_publish(ProtocolRequirement::H2Required);
        2067  +
        let action = OriginAdmission::publish_action_without_driving(
        2068  +
            &admission,
        2069  +
            requesting_cell.id().partition(),
        2070  +
            demand,
        2071  +
        )
        2072  +
        .expect("peer demand did not prepare publication");
        2073  +
        2074  +
        drop(action);
        2075  +
        2076  +
        drop(take_ready_h2(&requesting_cell, waiter));
        2077  +
        assert_eq!(0, admission.ordered_demand_count_for_test());
        2078  +
        assert!(OriginCell::close_h2(
        2079  +
            &connection_cell,
        2080  +
            generation,
        2081  +
            CloseReason::PoolDropped,
        2082  +
        ));
        2083  +
    }
        2084  +
        2085  +
    #[test]
        2086  +
    fn requesting_cell_cancellation_closes_an_in_flight_publication_fence() {
        2087  +
        let (admission, connection_cell, requesting_cell) =
        2088  +
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
        2089  +
        let (generation, _connection, _physical) =
        2090  +
            install_bounded_h2(&admission, &connection_cell, 1);
        2091  +
        let (waiter, demand) =
        2092  +
            requesting_cell.register_waiter_without_publish(ProtocolRequirement::H2Required);
        2093  +
        let action = OriginAdmission::publish_action_without_driving(
        2094  +
            &admission,
        2095  +
            requesting_cell.id().partition(),
        2096  +
            demand,
        2097  +
        )
        2098  +
        .expect("peer demand did not prepare publication");
        2099  +
        2100  +
        assert!(OriginCell::cancel_waiter(&requesting_cell, waiter));
        2101  +
        OriginAdmission::drive(Some(action));
        2102  +
        2103  +
        assert_eq!(0, requesting_cell.snapshot().retained);
        2104  +
        assert_eq!(0, admission.ordered_demand_count_for_test());
        2105  +
        assert_eq!(0, admission.available_capacity_for_test());
        2106  +
        assert_eq!(Some(generation), connection_cell.accepting_h2_generation());
        2107  +
        assert!(OriginCell::close_h2(
        2108  +
            &connection_cell,
        2109  +
            generation,
        2110  +
            CloseReason::PoolDropped,
        2111  +
        ));
        2112  +
    }
        2113  +
        2114  +
    #[test]
        2115  +
    fn stale_publication_retries_against_a_replacement_generation() {
        2116  +
        let (admission, connection_cell, requesting_cell) =
        2117  +
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
        2118  +
        let (first, _first_connection, _first_physical) =
        2119  +
            install_bounded_h2(&admission, &connection_cell, 1);
        2120  +
        let (waiter, demand) =
        2121  +
            requesting_cell.register_waiter_without_publish(ProtocolRequirement::H2Required);
        2122  +
        let action = OriginAdmission::publish_action_without_driving(
        2123  +
            &admission,
        2124  +
            requesting_cell.id().partition(),
        2125  +
            demand,
        2126  +
        )
        2127  +
        .expect("peer demand did not prepare publication");
        2128  +
        2129  +
        assert!(OriginCell::close_h2(
        2130  +
            &connection_cell,
        2131  +
            first,
        2132  +
            CloseReason::ProtocolClosed
        2133  +
        ));
        2134  +
        let (second, _second_connection, _second_physical) =
        2135  +
            install_bounded_h2(&admission, &connection_cell, 2);
        2136  +
        OriginAdmission::drive(Some(action));
        2137  +
        2138  +
        let activation = take_ready_h2(&requesting_cell, waiter);
        2139  +
        assert_eq!(second, activation.generation());
        2140  +
        drop(activation);
        2141  +
        assert!(OriginCell::close_h2(
        2142  +
            &connection_cell,
        2143  +
            second,
        2144  +
            CloseReason::PoolDropped
        2145  +
        ));
        2146  +
    }
        2147  +
        2148  +
    #[test]
        2149  +
    fn stale_peer_route_republishes_demand_to_a_replacement_generation() {
        2150  +
        let (admission, connection_cell, requesting_cell) =
        2151  +
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
        2152  +
        let (first, _first_connection, _first_physical) =
        2153  +
            install_bounded_h2(&admission, &connection_cell, 1);
        2154  +
        let (waiter, demand) =
        2155  +
            requesting_cell.register_waiter_without_publish(ProtocolRequirement::H2Required);
        2156  +
        assert!(OriginCell::install_h2_route(
        2157  +
            &requesting_cell,
        2158  +
            h2::H2Route::new(&connection_cell, first),
        2159  +
            &EligibilityGroup::Pool,
        2160  +
            demand.id_for_test(),
        2161  +
        ));
        2162  +
        2163  +
        assert!(OriginCell::close_h2(
        2164  +
            &connection_cell,
        2165  +
            first,
        2166  +
            CloseReason::ProtocolClosed
        2167  +
        ));
        2168  +
        let (second, _second_connection, _second_physical) =
        2169  +
            install_bounded_h2(&admission, &connection_cell, 2);
        2170  +
        OriginCell::service_peer_h2_waiters(&requesting_cell);
        2171  +
        let activation = take_ready_h2(&requesting_cell, waiter);
        2172  +
        assert_eq!(second, activation.generation());
        2173  +
        drop(activation);
        2174  +
        assert!(OriginCell::close_h2(
        2175  +
            &connection_cell,
        2176  +
            second,
        2177  +
            CloseReason::PoolDropped
        2178  +
        ));
        2179  +
    }
        2180  +
        2181  +
    #[test]
        2182  +
    fn direct_selection_removes_a_stale_peer_route() {
        2183  +
        let (admission, connection_cell, requesting_cell) =
        2184  +
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
        2185  +
        let (generation, _connection, _physical) =
        2186  +
            install_bounded_h2(&admission, &connection_cell, 1);
        2187  +
        let waiter = OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H2Required);
        2188  +
        drop(take_ready_h2(&requesting_cell, waiter));
        2189  +
        2190  +
        assert!(OriginCell::close_h2(
        2191  +
            &connection_cell,
        2192  +
            generation,
        2193  +
            CloseReason::ProtocolClosed,
        2194  +
        ));
        2195  +
        assert!(OriginCell::select_h2(&requesting_cell).is_none());
        2196  +
        assert!(
        2197  +
            !requesting_cell.state.lock().h2.has_visible_h2(),
        2198  +
            "direct selection retained a stale peer route"
        2199  +
        );
        2200  +
    }
        2201  +
        2202  +
    #[test]
        2203  +
    fn open_peer_route_allows_concurrent_prospective_activations() {
        2204  +
        let (admission, connection_cell, requesting_cell) =
        2205  +
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
        2206  +
        let (generation, _connection, _physical) =
        2207  +
            install_bounded_h2(&admission, &connection_cell, 1);
        2208  +
        let waiter = OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H2Required);
        2209  +
        drop(take_ready_h2(&requesting_cell, waiter));
        2210  +
        2211  +
        let first = OriginCell::select_h2(&requesting_cell)
        2212  +
            .expect("first direct peer activation was not selected");
        2213  +
        let second = OriginCell::select_h2(&requesting_cell)
        2214  +
            .expect("open peer route serialized the second activation");
        2215  +
        assert_eq!(generation, first.generation());
        2216  +
        assert_eq!(generation, second.generation());
        2217  +
        assert_eq!(Some((2, 0)), connection_cell.h2_request_counts(generation));
        2218  +
        drop(first);
        2219  +
        drop(second);
        2220  +
        assert!(OriginCell::close_h2(
        2221  +
            &connection_cell,
        2222  +
            generation,
        2223  +
            CloseReason::PoolDropped
        2224  +
        ));
        2225  +
    }
        2226  +
        2227  +
    #[test]
        2228  +
    fn peer_generation_gate_preserves_prepublication_order() {
        2229  +
        let (admission, connection_cell, requesting_cell) =
        2230  +
            bounded_peer_cells(1, EligibilityGroup::Pool, EligibilityGroup::Pool);
        2231  +
        let (generation, _connection, _physical) =
        2232  +
            install_bounded_h2(&admission, &connection_cell, 1);
        2233  +
        let (first, demand) =
        2234  +
            requesting_cell.register_waiter_without_publish(ProtocolRequirement::H2Required);
        2235  +
        let second = OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H2Required);
        2236  +
        let action = OriginAdmission::publish_action_without_driving(
        2237  +
            &admission,
        2238  +
            requesting_cell.id().partition(),
        2239  +
            demand,
        2240  +
        )
        2241  +
        .expect("peer demand did not prepare publication");
        2242  +
        OriginAdmission::drive(Some(action));
        2243  +
        let third = OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H2Required);
        2244  +
        2245  +
        let first_activation = take_ready_h2(&requesting_cell, first);
        2246  +
        assert!(requesting_cell.take_ready_event(second).is_none());
        2247  +
        assert!(requesting_cell.take_ready_event(third).is_none());
        2248  +
        drop(first_activation);
        2249  +
        2250  +
        let second_activation = take_ready_h2(&requesting_cell, second);
        2251  +
        assert!(requesting_cell.take_ready_event(third).is_none());
        2252  +
        drop(second_activation);
        2253  +
        drop(take_ready_h2(&requesting_cell, third));
        2254  +
        assert!(OriginCell::close_h2(
        2255  +
            &connection_cell,
        2256  +
            generation,
        2257  +
            CloseReason::PoolDropped,
        2258  +
        ));
        2259  +
    }
 2247   2260   
}
 2248   2261   
 2249   2262   
#[cfg(all(test, smithy_http_client_loom))]
 2250   2263   
mod loom_tests {
 2251   2264   
    use super::*;
 2252   2265   
    use http_1x::uri::Scheme;
 2253   2266   
    use std::num::NonZeroUsize;
 2254   2267   
 2255   2268   
    fn bounded_cell() -> (Arc<OriginAdmission>, Arc<OriginCell>) {
 2256   2269   
        bounded_cell_with_limit(1)
@@ -2346,2359 +2471,2484 @@
 2366   2379   
            );
 2367   2380   
        });
 2368   2381   
    }
 2369   2382   
 2370   2383   
    #[test]
 2371   2384   
    fn h1_delivery_and_waiter_cancellation_preserve_the_sender() {
 2372   2385   
        loom::model(|| {
 2373   2386   
            let cell = unbounded_cell();
 2374   2387   
            let (connection, _physical) = ConnectionState::unbounded(connection_info(1));
 2375   2388   
            let selection = OriginCell::install_selected_h1(&cell, connection, H1Sender::test(11));
 2376         -
            let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        2389  +
            let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 2377   2390   
 2378   2391   
            let returning = loom::thread::spawn(move || drop(selection));
 2379   2392   
            let cancel_cell = cell.clone();
 2380   2393   
            let cancelling =
 2381   2394   
                loom::thread::spawn(move || OriginCell::cancel_waiter(&cancel_cell, waiter));
 2382   2395   
            returning.join().unwrap();
 2383   2396   
            assert!(cancelling.join().unwrap());
 2384   2397   
 2385   2398   
            assert_eq!((1, 1), cell.h1_counts());
 2386   2399   
            assert_eq!(0, cell.snapshot().retained);
 2387   2400   
            assert_eq!(
 2388   2401   
                11,
 2389   2402   
                OriginCell::select_h1(&cell)
 2390   2403   
                    .expect("sender was lost during return/cancel")
 2391   2404   
                    .test_sender_id()
 2392   2405   
            );
 2393   2406   
        });
 2394   2407   
    }
 2395   2408   
 2396   2409   
    #[test]
 2397   2410   
    fn returned_h1_and_establishment_race_for_one_waiter() {
 2398   2411   
        loom::model(|| {
 2399   2412   
            let cell = unbounded_cell();
 2400         -
            let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        2413  +
            let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 2401   2414   
            let AcquisitionEvent::Establish(permit) = cell
 2402   2415   
                .take_ready_event(waiter)
 2403   2416   
                .expect("unbounded miss did not start establishment")
 2404   2417   
            else {
 2405   2418   
                panic!("unbounded miss completed before establishment started");
 2406   2419   
            };
 2407   2420   
            assert!(cell.start_establishment(waiter));
 2408   2421   
            drop(permit);
 2409   2422   
 2410   2423   
            let (returning_connection, _returning_physical) =
 2411   2424   
                ConnectionState::unbounded(connection_info(1));
 2412   2425   
            let returning =
 2413   2426   
                OriginCell::install_selected_h1(&cell, returning_connection, H1Sender::test(11));
 2414   2427   
            let (fresh_connection, _fresh_physical) =
 2415   2428   
                ConnectionState::unbounded(connection_info(2));
 2416   2429   
            let fresh =
 2417   2430   
                OriginCell::install_selected_h1(&cell, fresh_connection, H1Sender::test(22));
 2418   2431   
 2419   2432   
            let returning = loom::thread::spawn(move || drop(returning));
 2420   2433   
            let completion_cell = cell.clone();
 2421   2434   
            let completing = loom::thread::spawn(move || {
 2422   2435   
                completion_cell.complete_establishment(waiter, AcquisitionResult::H1(fresh));
 2423   2436   
            });
 2424   2437   
            returning.join().unwrap();
 2425   2438   
            completing.join().unwrap();
 2426   2439   
 2427   2440   
            assert_eq!((2, 1), cell.h1_counts());
 2428   2441   
            let winner = cell
 2429   2442   
                .take_ready_h1(waiter)
 2430   2443   
                .expect("both acquisition results were lost");
 2431   2444   
            assert!(matches!(winner.test_sender_id(), 11 | 22));
 2432   2445   
            drop(winner);
 2433   2446   
            assert_eq!((2, 2), cell.h1_counts());
 2434   2447   
        });
 2435   2448   
    }
 2436   2449   
 2437   2450   
    #[test]
 2438   2451   
    fn first_establishment_poll_races_returned_h1() {
 2439   2452   
        loom::model(|| {
 2440   2453   
            let cell = unbounded_cell();
 2441         -
            let waiter = cell.register_waiter(ProtocolRequirement::H1Compatible);
        2454  +
            let waiter = OriginCell::register_waiter(&cell, ProtocolRequirement::H1Compatible);
 2442   2455   
            let AcquisitionEvent::Establish(permit) = cell
 2443   2456   
                .take_ready_event(waiter)
 2444   2457   
                .expect("unbounded miss did not prepare establishment")
 2445   2458   
            else {
 2446   2459   
                panic!("unbounded miss completed before establishment was prepared");
 2447   2460   
            };
 2448   2461   
 2449   2462   
            let (returning_connection, _returning_physical) =
 2450   2463   
                ConnectionState::unbounded(connection_info(1));
 2451   2464   
            let returning =
@@ -2498,2511 +2558,2572 @@
 2518   2531   
    fn peer_reuse_and_request_cancellation_preserve_the_sender() {
 2519   2532   
        let mut model = loom::model::Builder::new();
 2520   2533   
        model.preemption_bound = Some(2);
 2521   2534   
        model.check(|| {
 2522   2535   
            let (admission, connection_cell, requesting_cell) =
 2523   2536   
                bounded_peer_cells(EligibilityGroup::Pool, EligibilityGroup::Pool);
 2524   2537   
            let lease = OriginAdmission::lease_for_test(&admission);
 2525   2538   
            let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
 2526   2539   
            let returning =
 2527   2540   
                OriginCell::install_selected_h1(&connection_cell, connection, H1Sender::test(11));
 2528         -
            let waiter = requesting_cell.register_waiter(ProtocolRequirement::H1Compatible);
        2541  +
            let waiter =
        2542  +
                OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H1Compatible);
 2529   2543   
 2530   2544   
            let returning = loom::thread::spawn(move || drop(returning));
 2531   2545   
            let cancel_requesting_cell = requesting_cell.clone();
 2532   2546   
            let cancelling = loom::thread::spawn(move || {
 2533   2547   
                OriginCell::cancel_waiter(&cancel_requesting_cell, waiter)
 2534   2548   
            });
 2535   2549   
            returning.join().unwrap();
 2536   2550   
            assert!(cancelling.join().unwrap());
 2537   2551   
 2538   2552   
            assert_eq!((1, 1), connection_cell.h1_counts());
@@ -2614,2628 +2721,2868 @@
 2634   2648   
                AcquisitionEvent::Complete(AcquisitionResult::H1(selection)) => {
 2635   2649   
                    drop(selection);
 2636   2650   
                }
 2637   2651   
                AcquisitionEvent::Establish(permit) => {
 2638   2652   
                    assert!(OriginCell::cancel_waiter(&requesting_cell, waiter));
 2639   2653   
                    drop(permit);
 2640   2654   
                }
 2641   2655   
                AcquisitionEvent::Complete(AcquisitionResult::Failed(error)) => {
 2642   2656   
                    panic!("unexpected establishment failure: {error}")
 2643   2657   
                }
        2658  +
                AcquisitionEvent::Complete(AcquisitionResult::Reacquire) => {
        2659  +
                    panic!("HTTP/1 reuse model requested reacquisition")
        2660  +
                }
        2661  +
                AcquisitionEvent::Complete(AcquisitionResult::H2(_)) => {
        2662  +
                    panic!("HTTP/1 reuse model received an HTTP/2 activation")
        2663  +
                }
 2644   2664   
            }
 2645   2665   
            assert_eq!(0, requesting_cell.snapshot().retained);
 2646   2666   
            assert_eq!(1, admission.available_capacity_for_test());
 2647   2667   
            admission.clear_modeled_cells_for_test();
 2648   2668   
        });
 2649   2669   
    }
 2650   2670   
 2651   2671   
    #[test]
 2652   2672   
    fn reclaim_and_connection_close_release_exactly_one_capacity_slot() {
 2653   2673   
        let mut model = loom::model::Builder::new();
 2654   2674   
        model.preemption_bound = Some(2);
 2655   2675   
        model.check(|| {
 2656   2676   
            let (admission, connection_cell, requesting_cell) = bounded_peer_cells(
 2657   2677   
                EligibilityGroup::Partition(PartitionId::from_index(1)),
 2658   2678   
                EligibilityGroup::Partition(PartitionId::from_index(2)),
 2659   2679   
            );
 2660   2680   
            let lease = OriginAdmission::lease_for_test(&admission);
 2661   2681   
            let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
 2662   2682   
            let returning = OriginCell::install_selected_h1(
 2663   2683   
                &connection_cell,
 2664   2684   
                connection.clone(),
 2665   2685   
                H1Sender::test(11),
 2666   2686   
            );
 2667   2687   
            let close = H1CloseHandle::new(&connection_cell, &connection);
 2668         -
            let waiter = requesting_cell.register_waiter(ProtocolRequirement::H1Compatible);
 2669         -
            let local_waiter = connection_cell.register_waiter(ProtocolRequirement::H1Compatible);
        2688  +
            let waiter =
        2689  +
                OriginCell::register_waiter(&requesting_cell, ProtocolRequirement::H1Compatible);
        2690  +
            let local_waiter =
        2691  +
                OriginCell::register_waiter(&connection_cell, ProtocolRequirement::H1Compatible);
 2670   2692   
 2671   2693   
            let returning = loom::thread::spawn(move || drop(returning));
 2672   2694   
            let closing = loom::thread::spawn(move || close.close(CloseReason::Poisoned));
 2673   2695   
            returning.join().unwrap();
 2674   2696   
            let close_won = closing.join().unwrap();
 2675   2697   
 2676   2698   
            assert_eq!(
 2677   2699   
                !close_won,
 2678   2700   
                connection_cell.state.lock().reuse.local_turn_owed(),
 2679   2701   
                "only a completed reclaim may earn the connection-owning cell a local fairness turn"
 2680   2702   
            );
 2681   2703   
 2682   2704   
            let replacement = OriginCell::take_ready_lease(&requesting_cell, waiter)
 2683   2705   
                .expect("close/reclaim race did not deliver released capacity");
 2684   2706   
            assert_eq!((0, 0), connection_cell.h1_counts());
 2685   2707   
            assert_eq!(0, admission.available_capacity_for_test());
 2686   2708   
            assert!(OriginCell::cancel_waiter(&connection_cell, local_waiter));
 2687   2709   
            drop(replacement);
 2688   2710   
            assert_eq!(1, admission.available_capacity_for_test());
 2689   2711   
            admission.clear_modeled_cells_for_test();
 2690   2712   
        });
 2691   2713   
    }
 2692   2714   
 2693   2715   
    #[test]
 2694   2716   
    fn delivery_and_cancellation_race_refunnels_capacity() {
 2695   2717   
        loom::model(|| {
 2696   2718   
            let (admission, cell) = bounded_cell();
 2697   2719   
            let (first, demand) =
 2698   2720   
                cell.register_waiter_without_publish(ProtocolRequirement::H1Compatible);
 2699   2721   
            let mut delivery =
 2700   2722   
                OriginAdmission::publish_without_driving(&admission, cell.id().partition(), demand)
 2701   2723   
                    .unwrap();
 2702   2724   
            assert!(
 2703   2725   
                delivery.materialize_for_test(),
 2704   2726   
                "capacity delivery did not materialize"
 2705   2727   
            );
 2706   2728   
 2707   2729   
            let delivery_cell = cell.clone();
 2708   2730   
            let deliver = loom::thread::spawn(move || {
 2709   2731   
                drop(OriginCell::receive_delivery(&delivery_cell, delivery));
 2710   2732   
            });
 2711   2733   
            let cancel_cell = cell.clone();
 2712   2734   
            let cancel =
 2713   2735   
                loom::thread::spawn(move || OriginCell::cancel_waiter(&cancel_cell, first));
 2714   2736   
            deliver.join().unwrap();
 2715   2737   
            cancel.join().unwrap();
 2716   2738   
 2717   2739   
            assert_eq!(1, admission.available_capacity_for_test());
 2718   2740   
            admission.clear_modeled_cells_for_test();
 2719   2741   
        });
 2720   2742   
    }
        2743  +
        2744  +
    #[test]
        2745  +
    fn h2_route_installation_races_requesting_cell_cancellation() {
        2746  +
        let mut model = loom::model::Builder::new();
        2747  +
        model.preemption_bound = Some(2);
        2748  +
        model.check(|| {
        2749  +
            let (admission, connection_cell, requesting_cell) =
        2750  +
                bounded_peer_cells(EligibilityGroup::Pool, EligibilityGroup::Pool);
        2751  +
            let lease = OriginAdmission::lease_for_test(&admission);
        2752  +
            let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
        2753  +
            let generation = OriginCell::install_h2_for_test(&connection_cell, connection, 1, None);
        2754  +
            let (waiter, demand) =
        2755  +
                requesting_cell.register_waiter_without_publish(ProtocolRequirement::H2Required);
        2756  +
            let route = h2::H2Route::new(&connection_cell, generation);
        2757  +
        2758  +
            let install_cell = requesting_cell.clone();
        2759  +
            let installing = loom::thread::spawn(move || {
        2760  +
                OriginCell::install_h2_route(
        2761  +
                    &install_cell,
        2762  +
                    route,
        2763  +
                    &EligibilityGroup::Pool,
        2764  +
                    demand.id_for_test(),
        2765  +
                )
        2766  +
            });
        2767  +
            let cancel_cell = requesting_cell.clone();
        2768  +
            let cancelling =
        2769  +
                loom::thread::spawn(move || OriginCell::cancel_waiter(&cancel_cell, waiter));
        2770  +
            let _installed = installing.join().unwrap();
        2771  +
            assert!(cancelling.join().unwrap());
        2772  +
        2773  +
            assert_eq!(0, requesting_cell.snapshot().retained);
        2774  +
            assert_eq!(0, admission.ordered_demand_count_for_test());
        2775  +
            assert_eq!(0, admission.available_capacity_for_test());
        2776  +
            assert!(OriginCell::close_h2(
        2777  +
                &connection_cell,
        2778  +
                generation,
        2779  +
                CloseReason::PoolDropped,
        2780  +
            ));
        2781  +
            assert_eq!(1, admission.available_capacity_for_test());
        2782  +
            admission.clear_modeled_cells_for_test();
        2783  +
        });
        2784  +
    }
        2785  +
        2786  +
    #[test]
        2787  +
    fn h2_publication_acknowledgement_races_generation_close_and_route_service() {
        2788  +
        let mut model = loom::model::Builder::new();
        2789  +
        model.preemption_bound = Some(3);
        2790  +
        model.check(|| {
        2791  +
            let (admission, connection_cell, requesting_cell) =
        2792  +
                bounded_peer_cells(EligibilityGroup::Pool, EligibilityGroup::Pool);
        2793  +
            let lease = OriginAdmission::lease_for_test(&admission);
        2794  +
            let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
        2795  +
            let generation = OriginCell::install_h2_for_test(&connection_cell, connection, 1, None);
        2796  +
            let (waiter, demand) =
        2797  +
                requesting_cell.register_waiter_without_publish(ProtocolRequirement::H2Required);
        2798  +
            let action = OriginAdmission::publish_action_without_driving(
        2799  +
                &admission,
        2800  +
                requesting_cell.id().partition(),
        2801  +
                demand,
        2802  +
            )
        2803  +
            .expect("peer demand did not prepare publication");
        2804  +
        2805  +
            let publishing = loom::thread::spawn(move || {
        2806  +
                OriginAdmission::drive(Some(action));
        2807  +
            });
        2808  +
            let closing_cell = connection_cell.clone();
        2809  +
            let closing = loom::thread::spawn(move || {
        2810  +
                OriginCell::close_h2(&closing_cell, generation, CloseReason::Poisoned)
        2811  +
            });
        2812  +
            let servicing_cell = requesting_cell.clone();
        2813  +
            let servicing = loom::thread::spawn(move || {
        2814  +
                OriginCell::service_peer_h2_waiters(&servicing_cell);
        2815  +
            });
        2816  +
        2817  +
            publishing.join().unwrap();
        2818  +
            assert!(closing.join().unwrap());
        2819  +
            servicing.join().unwrap();
        2820  +
        2821  +
            assert!(
        2822  +
                OriginCell::cancel_waiter(&requesting_cell, waiter),
        2823  +
                "publication acknowledgement lost the live demand"
        2824  +
            );
        2825  +
            assert_eq!(0, requesting_cell.snapshot().retained);
        2826  +
            assert_eq!(0, admission.ordered_demand_count_for_test());
        2827  +
            assert_eq!(1, admission.available_capacity_for_test());
        2828  +
            admission.clear_modeled_cells_for_test();
        2829  +
        });
        2830  +
    }
        2831  +
        2832  +
    #[test]
        2833  +
    fn h2_publication_close_race_preserves_capacity_ownership() {
        2834  +
        let mut model = loom::model::Builder::new();
        2835  +
        model.preemption_bound = Some(2);
        2836  +
        model.check(|| {
        2837  +
            let (admission, connection_cell, requesting_cell) =
        2838  +
                bounded_peer_cells(EligibilityGroup::Pool, EligibilityGroup::Pool);
        2839  +
            let lease = OriginAdmission::lease_for_test(&admission);
        2840  +
            let (connection, _physical) = ConnectionState::bounded(connection_info(1), lease);
        2841  +
            let generation = OriginCell::install_h2_for_test(&connection_cell, connection, 1, None);
        2842  +
            let (waiter, demand) =
        2843  +
                requesting_cell.register_waiter_without_publish(ProtocolRequirement::H2Required);
        2844  +
            let action = OriginAdmission::publish_action_without_driving(
        2845  +
                &admission,
        2846  +
                requesting_cell.id().partition(),
        2847  +
                demand,
        2848  +
            )
        2849  +
            .expect("peer demand did not prepare publication");
        2850  +
        2851  +
            let publishing = loom::thread::spawn(move || {
        2852  +
                OriginAdmission::drive(Some(action));
        2853  +
            });
        2854  +
            let closing_cell = connection_cell.clone();
        2855  +
            let closing = loom::thread::spawn(move || {
        2856  +
                OriginCell::close_h2(&closing_cell, generation, CloseReason::Poisoned)
        2857  +
            });
        2858  +
            publishing.join().unwrap();
        2859  +
            assert!(closing.join().unwrap());
        2860  +
        2861  +
            assert!(OriginCell::cancel_waiter(&requesting_cell, waiter));
        2862  +
            assert_eq!(0, requesting_cell.snapshot().retained);
        2863  +
            assert_eq!(0, admission.ordered_demand_count_for_test());
        2864  +
            assert_eq!(1, admission.available_capacity_for_test());
        2865  +
            admission.clear_modeled_cells_for_test();
        2866  +
        });
        2867  +
    }
 2721   2868   
}