diff --git a/control_plane/attachment_service/src/pageserver_client.rs b/control_plane/attachment_service/src/pageserver_client.rs index 8237229d7b..f0f7d61002 100644 --- a/control_plane/attachment_service/src/pageserver_client.rs +++ b/control_plane/attachment_service/src/pageserver_client.rs @@ -101,6 +101,15 @@ impl PageserverClient { ) } + pub(crate) async fn tenant_heatmap_upload(&self, tenant_id: TenantShardId) -> Result<()> { + measured_request!( + "tenant_heatmap_upload", + crate::metrics::Method::Post, + &self.node_id_label, + self.inner.tenant_heatmap_upload(tenant_id).await + ) + } + pub(crate) async fn location_config( &self, tenant_shard_id: TenantShardId, diff --git a/control_plane/attachment_service/src/service.rs b/control_plane/attachment_service/src/service.rs index a9b3997419..d26212fe81 100644 --- a/control_plane/attachment_service/src/service.rs +++ b/control_plane/attachment_service/src/service.rs @@ -3409,6 +3409,14 @@ impl Service { .join(",") ); + // Optimization: publish heatmaps immediately, so that secondary locations can start warming up. + for child in child_ids { + if let Err(e) = client.tenant_heatmap_upload(*child).await { + // Non-fatal, this is just an optimization + tracing::warn!("Failed to upload child {child} heatmap: {e}"); + } + } + if &response.new_shards != child_ids { // This should never happen: the pageserver should agree with us on how shard splits work. return Err(ApiError::InternalServerError(anyhow::anyhow!( diff --git a/pageserver/client/src/mgmt_api.rs b/pageserver/client/src/mgmt_api.rs index ab55d2b0a3..2d8572ddce 100644 --- a/pageserver/client/src/mgmt_api.rs +++ b/pageserver/client/src/mgmt_api.rs @@ -271,6 +271,17 @@ impl Client { Ok((status, progress)) } + pub async fn tenant_heatmap_upload(&self, tenant_id: TenantShardId) -> Result<()> { + let path = reqwest::Url::parse(&format!( + "{}/v1/tenant/{}/heatmap_upload", + self.mgmt_api_endpoint, tenant_id + )) + .expect("Cannot build URL"); + + self.request(Method::POST, path, ()).await?; + Ok(()) + } + pub async fn location_config( &self, tenant_shard_id: TenantShardId,