-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add memo trait interface and persistent memo implementation
This commit adds a first draft of a memo table trait and a persistent memo table implementation backed by SeaORM entities.
- Loading branch information
1 parent
06495a1
commit 4d60811
Showing
4 changed files
with
387 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,37 @@ | ||
use sea_orm::*; | ||
use sea_orm_migration::prelude::*; | ||
use thiserror::Error; | ||
|
||
mod migrator; | ||
use migrator::Migrator; | ||
|
||
mod entities; | ||
|
||
mod memo; | ||
use memo::MemoError; | ||
|
||
/// The filename of the SQLite database for migration. | ||
pub const DATABASE_FILENAME: &str = "sqlite.db"; | ||
/// The URL of the SQLite database for migration. | ||
pub const DATABASE_URL: &str = "sqlite:./sqlite.db?mode=rwc"; | ||
|
||
/// An error type wrapping all the different kinds of error the optimizer might raise. | ||
/// | ||
/// TODO more docs. | ||
#[derive(Error, Debug)] | ||
pub enum OptimizerError { | ||
#[error("SeaORM error")] | ||
Database(#[from] sea_orm::error::DbErr), | ||
#[error("Memo table logical error")] | ||
Memo(#[from] MemoError), | ||
#[error("unknown error")] | ||
Unknown, | ||
} | ||
|
||
/// Shorthand for a [`Result`] with an error type [`OptimizerError`]. | ||
pub type OptimizerResult<T> = Result<T, OptimizerError>; | ||
|
||
/// Applies all migrations. | ||
pub async fn migrate(db: &DatabaseConnection) -> Result<(), DbErr> { | ||
Migrator::refresh(db).await | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
use crate::OptimizerResult; | ||
use thiserror::Error; | ||
|
||
#[derive(Error, Debug)] | ||
/// The different kinds of errors that might occur while running operations on a memo table. | ||
pub enum MemoError { | ||
#[error("unknown group ID {0}")] | ||
UnknownGroup(i32), | ||
#[error("unknown logical expression ID {0}")] | ||
UnknownLogicalExpression(i32), | ||
#[error("unknown physical expression ID {0}")] | ||
UnknownPhysicalExpression(i32), | ||
#[error("invalid expression encountered")] | ||
InvalidExpression, | ||
} | ||
|
||
/// A trait representing an implementation of a memoization table. | ||
/// | ||
/// Note that we use [`trait_variant`] here in order to add bounds on every method. | ||
/// See this [blog post]( | ||
/// https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html#async-fn-in-public-traits) | ||
/// for more information. | ||
#[allow(dead_code)] | ||
#[trait_variant::make(Send)] | ||
pub trait Memo { | ||
/// A type representing a group in the Cascades framework. | ||
type Group; | ||
/// A type representing a unique identifier for a group. | ||
type GroupId; | ||
/// A type representing a logical expression. | ||
type LogicalExpression; | ||
/// A type representing a unique identifier for a logical expression. | ||
type LogicalExpressionId; | ||
/// A type representing a physical expression. | ||
type PhysicalExpression; | ||
/// A type representing a unique identifier for a physical expression. | ||
type PhysicalExpressionId; | ||
|
||
/// Retrieves a [`Self::Group`] given a [`Self::GroupId`]. | ||
/// | ||
/// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. | ||
async fn get_group(&self, group_id: Self::GroupId) -> OptimizerResult<Self::Group>; | ||
|
||
/// Retrieves a [`Self::LogicalExpression`] given a [`Self::LogicalExpressionId`]. | ||
/// | ||
/// If the logical expression does not exist, returns a [`MemoError::UnknownLogicalExpression`] | ||
/// error. | ||
async fn get_logical_expression( | ||
&self, | ||
logical_expression_id: Self::LogicalExpressionId, | ||
) -> OptimizerResult<Self::LogicalExpression>; | ||
|
||
/// Retrieves a [`Self::PhysicalExpression`] given a [`Self::PhysicalExpressionId`]. | ||
/// | ||
/// If the physical expression does not exist, returns a | ||
/// [`MemoError::UnknownPhysicalExpression`] error. | ||
async fn get_physical_expression( | ||
&self, | ||
physical_expression_id: Self::PhysicalExpressionId, | ||
) -> OptimizerResult<Self::PhysicalExpression>; | ||
|
||
/// Retrieves all of the logical expression "children" IDs of a group. | ||
/// | ||
/// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. | ||
async fn get_logical_children( | ||
&self, | ||
group_id: Self::GroupId, | ||
) -> OptimizerResult<Vec<Self::LogicalExpressionId>>; | ||
|
||
/// Retrieves all of the physical expression "children" IDs of a group. | ||
/// | ||
/// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. | ||
async fn get_physical_children( | ||
&self, | ||
group_id: Self::GroupId, | ||
) -> OptimizerResult<Vec<Self::PhysicalExpressionId>>; | ||
|
||
/// Updates / replaces a group's best physical plan (winner). Optionally returns the previous | ||
/// winner's physical expression ID. | ||
/// | ||
/// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. | ||
async fn update_group_winner( | ||
&self, | ||
group_id: Self::GroupId, | ||
physical_expression_id: Self::PhysicalExpressionId, | ||
) -> OptimizerResult<Option<Self::PhysicalExpressionId>>; | ||
|
||
/// Adds a logical expression to an existing group via its [`Self::GroupId`]. | ||
/// | ||
/// The caller is required to pass in a vector of `GroupId` that represent the child groups of | ||
/// the input expression. | ||
/// | ||
/// The caller is also required to set the `group_id` field of the input `logical_expression` | ||
/// to be equal to `group_id`, otherwise this function will return a | ||
/// [`MemoError::InvalidExpression`] error. | ||
/// | ||
/// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. | ||
async fn add_logical_expression_to_group( | ||
&self, | ||
group_id: Self::GroupId, | ||
logical_expression: Self::LogicalExpression, | ||
children: Vec<Self::GroupId>, | ||
) -> OptimizerResult<()>; | ||
|
||
/// Adds a physical expression to an existing group via its [`Self::GroupId`]. | ||
/// | ||
/// The caller is required to pass in a vector of `GroupId` that represent the child groups of | ||
/// the input expression. | ||
/// | ||
/// The caller is also required to set the `group_id` field of the input `physical_expression` | ||
/// to be equal to `group_id`, otherwise this function will return a | ||
/// [`MemoError::InvalidExpression`] error. | ||
/// | ||
/// If the group does not exist, returns a [`MemoError::UnknownGroup`] error. | ||
async fn add_physical_expression_to_group( | ||
&self, | ||
group_id: Self::GroupId, | ||
physical_expression: Self::PhysicalExpression, | ||
children: Vec<Self::GroupId>, | ||
) -> OptimizerResult<()>; | ||
|
||
/// Adds a new logical expression into the memo table, creating a new group if the expression | ||
/// does not already exist. | ||
/// | ||
/// The [`Self::LogicalExpression`] type should have some sort of mechanism for checking if | ||
/// the expression has been seen before, and if it has already been created, then the parent | ||
/// group ID should also be retrievable. | ||
/// | ||
/// If the expression already exists, then this function will return the [`Self::GroupId`] of | ||
/// the parent group and the corresponding (already existing) [`Self::LogicalExpressionId`]. | ||
/// | ||
/// If the expression does not exist, this function will create a new group and a new | ||
/// expression, returning brand new IDs for both. | ||
async fn add_logical_expression( | ||
&self, | ||
expression: Self::LogicalExpression, | ||
children: Vec<Self::LogicalExpressionId>, | ||
) -> OptimizerResult<(Self::GroupId, Self::LogicalExpressionId)>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
//! This module contains items related to the memo table, which is key to the Cascades query | ||
//! optimization framework. | ||
//! | ||
//! TODO more docs. | ||
mod persistent; | ||
|
||
mod interface; | ||
pub use interface::{Memo, MemoError}; |
Oops, something went wrong.