mod fetching;
pub(super) mod reader;
use crate::cluster::node::{NodeAddr, ResolvedContactPoint};
use crate::routing::Token;
use scylla_cql::frame::response::result::ColumnSpec;
use std::collections::HashMap;
use std::sync::Arc;
use thiserror::Error;
use uuid::Uuid;
pub use scylla_cql::frame::response::result::{
CollectionType, ColumnType, NativeType, UserDefinedType,
};
#[derive(Clone, Debug, Error)]
pub(crate) enum SingleKeyspaceMetadataError {
#[error(transparent)]
MissingUDT(MissingUserDefinedType),
#[error("Partition key column with position {0} is missing from metadata")]
IncompletePartitionKey(i32),
#[error("Clustering key column with position {0} is missing from metadata")]
IncompleteClusteringKey(i32),
}
pub(crate) struct Metadata {
pub(crate) peers: Vec<Peer>,
pub(crate) keyspaces: HashMap<String, Result<Keyspace, SingleKeyspaceMetadataError>>,
}
#[non_exhaustive] pub struct Peer {
pub host_id: Uuid,
pub address: NodeAddr,
pub tokens: Vec<Token>,
pub datacenter: Option<String>,
pub rack: Option<String>,
}
#[derive(Clone, Debug)]
pub(crate) enum UntranslatedEndpoint {
ContactPoint(ResolvedContactPoint),
Peer(PeerEndpoint),
}
impl UntranslatedEndpoint {
pub(crate) fn address(&self) -> NodeAddr {
match *self {
UntranslatedEndpoint::ContactPoint(ResolvedContactPoint { address, .. }) => {
NodeAddr::Untranslatable(address)
}
UntranslatedEndpoint::Peer(PeerEndpoint { address, .. }) => address,
}
}
pub(crate) fn set_port(&mut self, port: u16) {
let inner_addr = match self {
UntranslatedEndpoint::ContactPoint(ResolvedContactPoint { address, .. }) => address,
UntranslatedEndpoint::Peer(PeerEndpoint { address, .. }) => address.inner_mut(),
};
inner_addr.set_port(port);
}
}
#[derive(Clone, Debug)]
pub(crate) struct PeerEndpoint {
pub(crate) host_id: Uuid,
pub(crate) address: NodeAddr,
pub(crate) datacenter: Option<String>,
pub(crate) rack: Option<String>,
}
impl Peer {
pub(crate) fn to_peer_endpoint(&self) -> PeerEndpoint {
PeerEndpoint {
host_id: self.host_id,
address: self.address,
datacenter: self.datacenter.clone(),
rack: self.rack.clone(),
}
}
pub(crate) fn into_peer_endpoint_and_tokens(self) -> (PeerEndpoint, Vec<Token>) {
(
PeerEndpoint {
host_id: self.host_id,
address: self.address,
datacenter: self.datacenter,
rack: self.rack,
},
self.tokens,
)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct Keyspace {
pub strategy: Strategy,
pub durable_writes: bool,
pub tables: HashMap<String, Table>,
pub views: HashMap<String, MaterializedView>,
pub user_defined_types: HashMap<String, Arc<UserDefinedType<'static>>>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct Table {
pub columns: HashMap<String, Column>,
pub partition_key: Vec<String>,
pub clustering_key: Vec<String>,
pub partitioner: Option<String>,
pub(crate) pk_column_specs: Vec<ColumnSpec<'static>>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct MaterializedView {
pub view_metadata: Table,
pub base_table_name: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct Column {
pub typ: ColumnType<'static>,
pub kind: ColumnKind,
}
#[derive(Clone, Debug, Error)]
#[error("Missing UDT: {keyspace}, {name}")]
pub(crate) struct MissingUserDefinedType {
pub(crate) name: String,
pub(crate) keyspace: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum ColumnKind {
Regular,
Static,
Clustering,
PartitionKey,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ColumnKindFromStrError;
impl std::str::FromStr for ColumnKind {
type Err = ColumnKindFromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"regular" => Ok(Self::Regular),
"static" => Ok(Self::Static),
"clustering" => Ok(Self::Clustering),
"partition_key" => Ok(Self::PartitionKey),
_ => Err(ColumnKindFromStrError),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
#[expect(clippy::enum_variant_names)]
pub enum Strategy {
SimpleStrategy {
replication_factor: usize,
},
NetworkTopologyStrategy {
datacenter_repfactors: HashMap<String, usize>,
},
LocalStrategy, Other {
name: String,
data: HashMap<String, String>,
},
}
#[derive(Debug, Clone)]
pub(crate) struct ClientRoute {
pub(crate) connection_id: String,
pub(crate) host_id: Uuid,
pub(crate) hostname: String,
pub(crate) port: Option<u16>,
pub(crate) tls_port: Option<u16>,
}
#[derive(Debug, Default)] pub(crate) struct ClientRoutes {
pub(crate) routes: HashMap<Uuid, HashMap<String, ClientRoute>>,
}
impl Extend<ClientRoute> for ClientRoutes {
fn extend<T: IntoIterator<Item = ClientRoute>>(&mut self, into_iter: T) {
for route in into_iter {
self.routes
.entry(route.host_id)
.or_default() .insert(route.connection_id.clone(), route);
}
}
}
impl Metadata {
pub(crate) fn new_dummy(initial_peers: &[UntranslatedEndpoint]) -> Self {
let peers = initial_peers
.iter()
.enumerate()
.map(|(id, endpoint)| {
let token = ((id as u128) << 64) / initial_peers.len() as u128;
Peer {
address: endpoint.address(),
tokens: vec![Token::new(token as i64)],
datacenter: None,
rack: None,
host_id: Uuid::new_v4(),
}
})
.collect();
Metadata {
peers,
keyspaces: HashMap::new(),
}
}
}