-
Notifications
You must be signed in to change notification settings - Fork 245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: configurable caching for postgres with support for tracing #5082
feat: configurable caching for postgres with support for tracing #5082
Conversation
CodSpeed Performance ReportMerging #5082 will not alter performanceComparing Summary
|
QuaintManager::Postgres { | ||
url, | ||
tls_manager, | ||
is_tracing_enabled: false, | ||
} => { | ||
use crate::connector::PostgreSqlWithDefaultCache; | ||
Ok(Box::new(PostgreSqlWithDefaultCache::new(url.clone(), tls_manager).await?) as Self::Connection) | ||
} | ||
|
||
#[cfg(feature = "postgresql-native")] | ||
QuaintManager::Postgres { | ||
url, | ||
tls_manager, | ||
is_tracing_enabled: true, | ||
} => { | ||
use crate::connector::PostgreSqlWithTracingCache; | ||
Ok(Box::new(PostgreSqlWithTracingCache::new(url.clone(), tls_manager).await?) as Self::Connection) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary:
- when
is_tracing_enabled
, we use the tracing cache (crate::connector::PostgreSqlWithTracingCache
) - when
!is_tracing_enabled
, we use the default cache (crate::connector::PostgreSqlWithDefaultCache
)
#[tokio::test] | ||
async fn tracing_lru_cache_reuses_queries_within_capacity() { | ||
run_with_client(|client| async move { | ||
let cache = TracingLruCache::with_capacity(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's expand this test case with a higher capacity, e.g., 3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
#[tokio::test] | ||
async fn prepared_statement_lru_cache_reuses_statements_within_capacity() { | ||
run_with_client(|client| async move { | ||
let cache = PreparedStatementLruCache::with_capacity(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's expand this test case with a higher capacity, e.g., 3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
#[tokio::test] | ||
async fn prepared_statement_lru_cache_reuses_queries_within_capacity() { | ||
run_with_client(|client| async move { | ||
let cache = PreparedStatementLruCache::with_capacity(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's expand this test case with a higher capacity, e.g., 3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
match self.cache.get(sql, types).await { | ||
Some(statement) => Ok(statement), | ||
None => { | ||
let stmt = client.prepare_typed(sql, types).await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, here's why we need Result
in the function signature's return type
/// Types that can be used as a cache for prepared queries and statements. | ||
#[async_trait] | ||
pub trait QueryCache: From<CacheSettings> + Send + Sync { | ||
/// The type that is returned when a prepared query is requested from the cache. | ||
type Query<'a>: PreparedQuery; | ||
|
||
/// Retrieve a prepared query. | ||
async fn get_query<'a>(&self, client: &Client, sql: &'a str, types: &[Type]) -> Result<Self::Query<'a>, Error>; | ||
|
||
/// Retrieve a prepared statement. | ||
/// | ||
/// This is useful in scenarios that require direct access to a prepared statement, | ||
/// e.g. describing a query. | ||
async fn get_statement(&self, client: &Client, sql: &str, types: &[Type]) -> Result<Statement, Error>; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! This is so much better than having two separate caches.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job! I've left a nit. Please wait for @aqrln's review as well before merging
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code looks amazing, and the client tests pass with pnpm --filter @prisma/client test:functional:code --provider postgresql --preview-features tracing
locally.
The lack of execute_typed
in tokio_postgres
is a bummer but I think it only affects createMany
.
This PR fixes https://github.com/prisma/team-orm/issues/1331.