utils: move ShardStripeSize into shard module (#12640)

## Problem

`ShardStripeSize` will be used in the compute spec and internally in the
communicator. It shouldn't require pulling in all of `pageserver_api`.

## Summary of changes

Move `ShardStripeSize` into `utils::shard`, along with other basic shard
types. Also remove the `Default` implementation, to discourage clients
from falling back to a default (it's generally a footgun).

The type is still re-exported from `pageserver_api::shard`, along with
all the other shard types.
This commit is contained in:
Erik Grinaker
2025-07-21 12:56:20 +02:00
committed by GitHub
parent 1406bdc6a8
commit e181b996c3
12 changed files with 49 additions and 67 deletions

View File

@@ -65,7 +65,6 @@ use jsonwebtoken::jwk::{
OctetKeyPairParameters, OctetKeyPairType, PublicKeyUse, OctetKeyPairParameters, OctetKeyPairType, PublicKeyUse,
}; };
use nix::sys::signal::{Signal, kill}; use nix::sys::signal::{Signal, kill};
use pageserver_api::shard::ShardStripeSize;
use pem::Pem; use pem::Pem;
use reqwest::header::CONTENT_TYPE; use reqwest::header::CONTENT_TYPE;
use safekeeper_api::PgMajorVersion; use safekeeper_api::PgMajorVersion;
@@ -77,6 +76,7 @@ use spki::{SubjectPublicKeyInfo, SubjectPublicKeyInfoRef};
use tracing::debug; use tracing::debug;
use url::Host; use url::Host;
use utils::id::{NodeId, TenantId, TimelineId}; use utils::id::{NodeId, TenantId, TimelineId};
use utils::shard::ShardStripeSize;
use crate::local_env::LocalEnv; use crate::local_env::LocalEnv;
use crate::postgresql_conf::PostgresConf; use crate::postgresql_conf::PostgresConf;

View File

@@ -69,22 +69,6 @@ impl Hash for ShardIdentity {
} }
} }
/// Stripe size in number of pages
#[derive(Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Debug)]
pub struct ShardStripeSize(pub u32);
impl Default for ShardStripeSize {
fn default() -> Self {
DEFAULT_STRIPE_SIZE
}
}
impl std::fmt::Display for ShardStripeSize {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
/// Layout version: for future upgrades where we might change how the key->shard mapping works /// Layout version: for future upgrades where we might change how the key->shard mapping works
#[derive(Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash, Debug)] #[derive(Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash, Debug)]
pub struct ShardLayout(u8); pub struct ShardLayout(u8);

View File

@@ -25,6 +25,12 @@ pub struct ShardIndex {
pub shard_count: ShardCount, pub shard_count: ShardCount,
} }
/// Stripe size as number of pages.
///
/// NB: don't implement Default, so callers don't lazily use it by mistake. See DEFAULT_STRIPE_SIZE.
#[derive(Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Debug)]
pub struct ShardStripeSize(pub u32);
/// Formatting helper, for generating the `shard_id` label in traces. /// Formatting helper, for generating the `shard_id` label in traces.
pub struct ShardSlug<'a>(&'a TenantShardId); pub struct ShardSlug<'a>(&'a TenantShardId);
@@ -177,6 +183,12 @@ impl std::fmt::Display for ShardCount {
} }
} }
impl std::fmt::Display for ShardStripeSize {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::fmt::Display for ShardSlug<'_> { impl std::fmt::Display for ShardSlug<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!( write!(

View File

@@ -8,6 +8,7 @@ use anyhow::anyhow;
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use futures::stream::FuturesUnordered; use futures::stream::FuturesUnordered;
use futures::{FutureExt as _, StreamExt as _}; use futures::{FutureExt as _, StreamExt as _};
use pageserver_api::shard::DEFAULT_STRIPE_SIZE;
use tonic::codec::CompressionEncoding; use tonic::codec::CompressionEncoding;
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use utils::logging::warn_slow; use utils::logging::warn_slow;
@@ -16,10 +17,9 @@ use crate::pool::{ChannelPool, ClientGuard, ClientPool, StreamGuard, StreamPool}
use crate::retry::Retry; use crate::retry::Retry;
use crate::split::GetPageSplitter; use crate::split::GetPageSplitter;
use compute_api::spec::PageserverProtocol; use compute_api::spec::PageserverProtocol;
use pageserver_api::shard::ShardStripeSize;
use pageserver_page_api as page_api; use pageserver_page_api as page_api;
use utils::id::{TenantId, TimelineId}; use utils::id::{TenantId, TimelineId};
use utils::shard::{ShardCount, ShardIndex, ShardNumber}; use utils::shard::{ShardCount, ShardIndex, ShardNumber, ShardStripeSize};
/// Max number of concurrent clients per channel (i.e. TCP connection). New channels will be spun up /// Max number of concurrent clients per channel (i.e. TCP connection). New channels will be spun up
/// when full. /// when full.
@@ -418,7 +418,7 @@ impl ShardSpec {
if stripe_size.is_none() && !count.is_unsharded() { if stripe_size.is_none() && !count.is_unsharded() {
return Err(anyhow!("stripe size must be given for sharded tenants")); return Err(anyhow!("stripe size must be given for sharded tenants"));
} }
let stripe_size = stripe_size.unwrap_or_default(); let stripe_size = stripe_size.unwrap_or(DEFAULT_STRIPE_SIZE);
// Validate the shard spec. // Validate the shard spec.
for (shard_id, url) in &urls { for (shard_id, url) in &urls {

View File

@@ -3,9 +3,9 @@ use std::collections::HashMap;
use bytes::Bytes; use bytes::Bytes;
use pageserver_api::key::rel_block_to_key; use pageserver_api::key::rel_block_to_key;
use pageserver_api::shard::{ShardStripeSize, key_to_shard_number}; use pageserver_api::shard::key_to_shard_number;
use pageserver_page_api as page_api; use pageserver_page_api as page_api;
use utils::shard::{ShardCount, ShardIndex, ShardNumber}; use utils::shard::{ShardCount, ShardIndex, ShardNumber, ShardStripeSize};
/// Splits GetPageRequests that straddle shard boundaries and assembles the responses. /// Splits GetPageRequests that straddle shard boundaries and assembles the responses.
/// TODO: add tests for this. /// TODO: add tests for this.

View File

@@ -4,7 +4,7 @@ use anyhow::Context;
use clap::Parser; use clap::Parser;
use pageserver_api::key::Key; use pageserver_api::key::Key;
use pageserver_api::reltag::{BlockNumber, RelTag, SlruKind}; use pageserver_api::reltag::{BlockNumber, RelTag, SlruKind};
use pageserver_api::shard::{ShardCount, ShardStripeSize}; use pageserver_api::shard::{DEFAULT_STRIPE_SIZE, ShardCount, ShardStripeSize};
#[derive(Parser)] #[derive(Parser)]
pub(super) struct DescribeKeyCommand { pub(super) struct DescribeKeyCommand {
@@ -128,7 +128,9 @@ impl DescribeKeyCommand {
// seeing the sharding placement might be confusing, so leave it out unless shard // seeing the sharding placement might be confusing, so leave it out unless shard
// count was given. // count was given.
let stripe_size = stripe_size.map(ShardStripeSize).unwrap_or_default(); let stripe_size = stripe_size
.map(ShardStripeSize)
.unwrap_or(DEFAULT_STRIPE_SIZE);
println!( println!(
"# placement with shard_count: {} and stripe_size: {}:", "# placement with shard_count: {} and stripe_size: {}:",
shard_count.0, stripe_size.0 shard_count.0, stripe_size.0

View File

@@ -2912,9 +2912,8 @@ static ZERO_PAGE: Bytes = Bytes::from_static(&[0u8; BLCKSZ as usize]);
mod tests { mod tests {
use hex_literal::hex; use hex_literal::hex;
use pageserver_api::models::ShardParameters; use pageserver_api::models::ShardParameters;
use pageserver_api::shard::ShardStripeSize;
use utils::id::TimelineId; use utils::id::TimelineId;
use utils::shard::{ShardCount, ShardNumber}; use utils::shard::{ShardCount, ShardNumber, ShardStripeSize};
use super::*; use super::*;
use crate::DEFAULT_PG_VERSION; use crate::DEFAULT_PG_VERSION;

View File

@@ -328,7 +328,7 @@ fn emergency_generations(
LocationMode::Attached(alc) => TenantStartupMode::Attached(( LocationMode::Attached(alc) => TenantStartupMode::Attached((
alc.attach_mode, alc.attach_mode,
alc.generation, alc.generation,
ShardStripeSize::default(), lc.shard.stripe_size,
)), )),
LocationMode::Secondary(_) => TenantStartupMode::Secondary, LocationMode::Secondary(_) => TenantStartupMode::Secondary,
}, },

View File

@@ -1,8 +1,8 @@
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use pageserver_api::shard::ShardStripeSize;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use utils::id::TimelineId; use utils::id::TimelineId;
use utils::lsn::Lsn; use utils::lsn::Lsn;
use utils::shard::ShardStripeSize;
/// Tenant shard manifest, stored in remote storage. Contains offloaded timelines and other tenant /// Tenant shard manifest, stored in remote storage. Contains offloaded timelines and other tenant
/// shard-wide information that must be persisted in remote storage. /// shard-wide information that must be persisted in remote storage.

View File

@@ -654,7 +654,7 @@ mod tests {
use pageserver_api::key::{DBDIR_KEY, Key, rel_block_to_key}; use pageserver_api::key::{DBDIR_KEY, Key, rel_block_to_key};
use pageserver_api::models::ShardParameters; use pageserver_api::models::ShardParameters;
use pageserver_api::reltag::RelTag; use pageserver_api::reltag::RelTag;
use pageserver_api::shard::ShardStripeSize; use pageserver_api::shard::DEFAULT_STRIPE_SIZE;
use utils::shard::ShardCount; use utils::shard::ShardCount;
use utils::sync::gate::GateGuard; use utils::sync::gate::GateGuard;
@@ -955,7 +955,7 @@ mod tests {
}); });
let child_params = ShardParameters { let child_params = ShardParameters {
count: ShardCount(2), count: ShardCount(2),
stripe_size: ShardStripeSize::default(), stripe_size: DEFAULT_STRIPE_SIZE,
}; };
let child0 = Arc::new_cyclic(|myself| StubTimeline { let child0 = Arc::new_cyclic(|myself| StubTimeline {
gate: Default::default(), gate: Default::default(),

View File

@@ -742,7 +742,7 @@ mod tests {
use std::str::FromStr; use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
use pageserver_api::shard::{ShardIdentity, ShardStripeSize}; use pageserver_api::shard::{DEFAULT_STRIPE_SIZE, ShardIdentity};
use postgres_ffi::{MAX_SEND_SIZE, PgMajorVersion}; use postgres_ffi::{MAX_SEND_SIZE, PgMajorVersion};
use tokio::sync::mpsc::error::TryRecvError; use tokio::sync::mpsc::error::TryRecvError;
use utils::id::{NodeId, TenantTimelineId}; use utils::id::{NodeId, TenantTimelineId};
@@ -786,19 +786,13 @@ mod tests {
MAX_SEND_SIZE, MAX_SEND_SIZE,
); );
let shard_0 = ShardIdentity::new( let shard_0 =
ShardNumber(0), ShardIdentity::new(ShardNumber(0), ShardCount(SHARD_COUNT), DEFAULT_STRIPE_SIZE)
ShardCount(SHARD_COUNT), .unwrap();
ShardStripeSize::default(),
)
.unwrap();
let shard_1 = ShardIdentity::new( let shard_1 =
ShardNumber(1), ShardIdentity::new(ShardNumber(1), ShardCount(SHARD_COUNT), DEFAULT_STRIPE_SIZE)
ShardCount(SHARD_COUNT), .unwrap();
ShardStripeSize::default(),
)
.unwrap();
let mut shards = HashMap::new(); let mut shards = HashMap::new();
@@ -806,7 +800,7 @@ mod tests {
let shard_id = ShardIdentity::new( let shard_id = ShardIdentity::new(
ShardNumber(shard_number), ShardNumber(shard_number),
ShardCount(SHARD_COUNT), ShardCount(SHARD_COUNT),
ShardStripeSize::default(), DEFAULT_STRIPE_SIZE,
) )
.unwrap(); .unwrap();
let (tx, rx) = tokio::sync::mpsc::channel::<Batch>(MSG_COUNT * 2); let (tx, rx) = tokio::sync::mpsc::channel::<Batch>(MSG_COUNT * 2);
@@ -934,12 +928,9 @@ mod tests {
MAX_SEND_SIZE, MAX_SEND_SIZE,
); );
let shard_0 = ShardIdentity::new( let shard_0 =
ShardNumber(0), ShardIdentity::new(ShardNumber(0), ShardCount(SHARD_COUNT), DEFAULT_STRIPE_SIZE)
ShardCount(SHARD_COUNT), .unwrap();
ShardStripeSize::default(),
)
.unwrap();
struct Sender { struct Sender {
tx: Option<tokio::sync::mpsc::Sender<Batch>>, tx: Option<tokio::sync::mpsc::Sender<Batch>>,
@@ -1088,19 +1079,13 @@ mod tests {
WAL_READER_BATCH_SIZE, WAL_READER_BATCH_SIZE,
); );
let shard_0 = ShardIdentity::new( let shard_0 =
ShardNumber(0), ShardIdentity::new(ShardNumber(0), ShardCount(SHARD_COUNT), DEFAULT_STRIPE_SIZE)
ShardCount(SHARD_COUNT), .unwrap();
ShardStripeSize::default(),
)
.unwrap();
let shard_1 = ShardIdentity::new( let shard_1 =
ShardNumber(1), ShardIdentity::new(ShardNumber(1), ShardCount(SHARD_COUNT), DEFAULT_STRIPE_SIZE)
ShardCount(SHARD_COUNT), .unwrap();
ShardStripeSize::default(),
)
.unwrap();
let mut shards = HashMap::new(); let mut shards = HashMap::new();
@@ -1108,7 +1093,7 @@ mod tests {
let shard_id = ShardIdentity::new( let shard_id = ShardIdentity::new(
ShardNumber(shard_number), ShardNumber(shard_number),
ShardCount(SHARD_COUNT), ShardCount(SHARD_COUNT),
ShardStripeSize::default(), DEFAULT_STRIPE_SIZE,
) )
.unwrap(); .unwrap();
let (tx, rx) = tokio::sync::mpsc::channel::<Batch>(MSG_COUNT * 2); let (tx, rx) = tokio::sync::mpsc::channel::<Batch>(MSG_COUNT * 2);

View File

@@ -981,7 +981,7 @@ mod tests {
use pageserver_api::models::utilization::test_utilization; use pageserver_api::models::utilization::test_utilization;
use pageserver_api::shard::ShardIdentity; use pageserver_api::shard::ShardIdentity;
use utils::id::TenantId; use utils::id::TenantId;
use utils::shard::{ShardCount, ShardNumber, TenantShardId}; use utils::shard::{ShardCount, ShardNumber, ShardStripeSize, TenantShardId};
use super::*; use super::*;
use crate::tenant_shard::IntentState; use crate::tenant_shard::IntentState;
@@ -1337,7 +1337,7 @@ mod tests {
let shard_identity = ShardIdentity::new( let shard_identity = ShardIdentity::new(
tenant_shard_id.shard_number, tenant_shard_id.shard_number,
tenant_shard_id.shard_count, tenant_shard_id.shard_count,
pageserver_api::shard::ShardStripeSize(1), ShardStripeSize(1),
) )
.unwrap(); .unwrap();
let mut shard = TenantShard::new( let mut shard = TenantShard::new(
@@ -1411,7 +1411,7 @@ mod tests {
let shard_identity = ShardIdentity::new( let shard_identity = ShardIdentity::new(
tenant_shard_id.shard_number, tenant_shard_id.shard_number,
tenant_shard_id.shard_count, tenant_shard_id.shard_count,
pageserver_api::shard::ShardStripeSize(1), ShardStripeSize(1),
) )
.unwrap(); .unwrap();
let mut shard = TenantShard::new( let mut shard = TenantShard::new(
@@ -1573,7 +1573,7 @@ mod tests {
let shard_identity = ShardIdentity::new( let shard_identity = ShardIdentity::new(
tenant_shard_id.shard_number, tenant_shard_id.shard_number,
tenant_shard_id.shard_count, tenant_shard_id.shard_count,
pageserver_api::shard::ShardStripeSize(1), ShardStripeSize(1),
) )
.unwrap(); .unwrap();
// 1 attached and 1 secondary. // 1 attached and 1 secondary.