use crate::db::{
QueryError,
commit::CommitSchemaFingerprint,
executor::EntityAuthority,
query::{
intent::{StructuralQuery, StructuralQueryCacheKey},
plan::PreparedQueryParameterContract,
preparation::PreparationWork,
},
schema::{
AcceptedSchemaRevision, AcceptedSchemaRuntimeRootIdentity, AcceptedSchemaSnapshot,
SchemaVersion,
},
session::AcceptedSchemaCatalogContext,
};
use std::rc::Rc;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub(in crate::db) enum QueryPlanVisibility {
StoreNotReady,
StoreReady,
#[cfg(feature = "sql")]
PrimaryOnly,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub(in crate::db) struct QueryPlanCacheKey {
entity_path: Rc<str>,
schema_identity: SchemaCacheIdentity,
visibility: QueryPlanVisibility,
structural_query: StructuralQueryCacheKey,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub(super) struct SchemaCacheIdentity {
runtime_root: AcceptedSchemaRuntimeRootIdentity,
revision: AcceptedSchemaRevision,
version: SchemaVersion,
fingerprint_method_version: u8,
fingerprint: CommitSchemaFingerprint,
}
impl SchemaCacheIdentity {
pub(super) const fn new(
runtime_root: AcceptedSchemaRuntimeRootIdentity,
revision: AcceptedSchemaRevision,
version: SchemaVersion,
fingerprint_method_version: u8,
fingerprint: CommitSchemaFingerprint,
) -> Self {
Self {
runtime_root,
revision,
version,
fingerprint_method_version,
fingerprint,
}
}
pub(super) fn from_accepted_schema_with_fingerprint(
accepted_schema: &AcceptedSchemaSnapshot,
fingerprint: CommitSchemaFingerprint,
runtime_root: AcceptedSchemaRuntimeRootIdentity,
revision: AcceptedSchemaRevision,
) -> Self {
Self::new(
runtime_root,
revision,
accepted_schema.persisted_snapshot().version(),
crate::db::schema::accepted_schema_cache_fingerprint_method_version(),
fingerprint,
)
}
pub(super) fn from_catalog(catalog: &AcceptedSchemaCatalogContext) -> Self {
Self::new(
catalog.runtime_root_identity(),
catalog.revision(),
catalog.schema_version(),
catalog.fingerprint_method_version(),
catalog.fingerprint(),
)
}
pub(super) const fn fingerprint(self) -> CommitSchemaFingerprint {
self.fingerprint
}
}
impl QueryPlanCacheKey {
fn from_authority_cache_inputs(
authority: &EntityAuthority,
schema_identity: SchemaCacheIdentity,
visibility: QueryPlanVisibility,
structural_query: StructuralQueryCacheKey,
) -> Self {
Self {
entity_path: authority.entity_path_handle(),
schema_identity,
visibility,
structural_query,
}
}
pub(super) fn for_authority_with_normalized_predicate_fingerprint(
authority: &EntityAuthority,
schema_identity: SchemaCacheIdentity,
visibility: QueryPlanVisibility,
query: &StructuralQuery,
normalized_predicate_fingerprint: Option<[u8; 32]>,
work: &PreparationWork<'_>,
) -> Result<Self, QueryError> {
Ok(Self::from_authority_cache_inputs(
authority,
schema_identity,
visibility,
query.structural_cache_key_with_normalized_predicate_fingerprint(
normalized_predicate_fingerprint,
work,
)?,
))
}
pub(super) fn for_authority_with_parameter_contract(
authority: &EntityAuthority,
schema_identity: SchemaCacheIdentity,
visibility: QueryPlanVisibility,
query: &StructuralQuery,
parameter_contract: PreparedQueryParameterContract,
work: &PreparationWork<'_>,
) -> Result<Self, QueryError> {
Ok(Self::from_authority_cache_inputs(
authority,
schema_identity,
visibility,
query.structural_cache_key_with_parameter_contract(parameter_contract, work)?,
))
}
}
#[cfg(test)]
mod tests {
use super::SchemaCacheIdentity;
use crate::db::{
integrity::DatabaseIncarnationId,
schema::{
AcceptedSchemaRevision, AcceptedSchemaRuntimeRootIdentity,
AcceptedSchemaRuntimeStoreRoot, SchemaVersion,
empty_accepted_schema_candidate_for_tests,
},
};
fn runtime_root(fill: u8) -> AcceptedSchemaRuntimeRootIdentity {
let candidate = empty_accepted_schema_candidate_for_tests(
"test::CacheIdentity",
AcceptedSchemaRevision::INITIAL,
);
AcceptedSchemaRuntimeRootIdentity::from_store_roots(
DatabaseIncarnationId::for_tests(fill),
&[AcceptedSchemaRuntimeStoreRoot::new(
"test::CacheIdentity",
Some(candidate.root()),
)],
)
.expect("cache identity root should admit")
}
#[test]
fn schema_cache_identity_rejects_mixed_runtime_roots() {
let first = SchemaCacheIdentity::new(
runtime_root(1),
AcceptedSchemaRevision::INITIAL,
SchemaVersion::initial(),
1,
[7; 16],
);
let second = SchemaCacheIdentity::new(
runtime_root(2),
AcceptedSchemaRevision::INITIAL,
SchemaVersion::initial(),
1,
[7; 16],
);
assert_ne!(first, second);
}
}
crate::retained::retained_fields!(QueryPlanCacheKey {
Self{entity_path,schema_identity,visibility,structural_query} => [entity_path,schema_identity,visibility,structural_query],
});
crate::retained::retained_copy!(QueryPlanVisibility);
crate::retained::retained_copy!(SchemaCacheIdentity);