Uh oh!
There was an error while loading. Please reload this page.
Extract catalog API to separate crate, change TableProvider::scan to take a trait rather than SessionState - #11516
Conversation
findepi
commented
Jul 17, 2024
This tries to implement the idea expressed in #10782 (comment) |
d5f5a77 to
5bbf5d7Compare8ad5111 to
0430691CompareUh oh!
There was an error while loading. Please reload this page.
0430691 to
6c399c2Comparefindepi
commented
Jul 17, 2024
Eventually all green. @jayzhan211@alamb@comphead you may want to take a look |
jayzhan211
commented
Jul 18, 2024
I think |
findepi
commented
Jul 18, 2024
@jayzhan211 admittedly i made some choices about what to put into CatalogSession (or however we want to call this) and what to keep outside requiring a downcast to SessionState. Of course, these choices remain pretty arbitrary. there may be things that CatalogSession should have but doesn't have yet, and also things that it got, but should be left out. |
I think this is similar to minimum dependencies what I'm thinking. The only difference is that I propose IMO struct is more sutiable for storing data, unlike trait that mainly used for sharing same behavior Given the dependency of TableProvider I found, we might need to find out the smaller context for FileFormatFactory and QueryPlanner. traitTableProvider{asyncfnscan(&self,context:&TableProviderContext,projection:Option<&Vec<usize>>,filters:&[Expr],limit:Option<usize>,) -> Result<Arc<dynExecutionPlan>>;}structTableProviderContext{FileFormatFactorySessionConfigExectuionPropsRuntimeEnvQueryPlanner}pubtraitQueryPlanner{/// Given a `LogicalPlan`, create an [`ExecutionPlan`] suitable for executionasyncfncreate_physical_plan(&self,logical_plan:&LogicalPlan,context:&QueryPlannerContext,) -> Result<Arc<dynExecutionPlan>>;}pubtraitFileFormatFactory:Sync + Send + GetExt{/// Initialize a [FileFormat] and configure based on session and command level optionsfncreate(&self,context:&FileFormatContext,format_options:&HashMap<String,String>,) -> Result<Arc<dynFileFormat>>;/// Initialize a [FileFormat] with all options set to default valuesfndefault(&self) -> Arc<dynFileFormat>;}But before that, we need to ensure those contexts won't end up the as the same thing in the long term |
findepi
commented
Jul 19, 2024
A publicly constructible struct is indeed different than a trait. Not sure we want that though, as it would limit evolvability. IMO a bigger question is what functionality does this new being provide. cc @alamb it would be good to hear your opinion, especially that you created the #10782 issue, which this PR is in response to. |
Given the current QueryPlanner is much complex, there is
|
findepi
commented
Jul 19, 2024
At runtime there are circular dependencies, unless we further limit amount of functionality available to the |
I doubt that |
I think there is clear dependency something close to // queryplanner cratetraitQueryPlanner{}implQueryPlannerforDefaultPlanner{}// fileformat cratetraitFileFormat{}implFileFormatforDefaultFile{// FileFormatContext that has all the higher level concept things above FileFormatfnscan(&self,FileFormatContext) -> Arc<QueryPlanner>{// able to downcast to planner }}// Table cratetraitTableProvider{}implTableProviderforDefaultTable{// arguments are all higher level trait without circular dependencyfn get_file(&self,plan) -> Arc<QueryPlanner>{// able to downcast to actual planner }fnget_planner(&self,fileformat) -> Arc<FileFormat>{// able to downcast to actual format}// TableProviderContext that has all the higher level concept things above TableProviderfnscan(&self,TableProviderContext)}Here is one example that I think we should fixed. We find the specific table from LogicalPlan::Dml(DmlStatement{
table_name,op:WriteOp::InsertInto,
..
}) => {let name = table_name.table();let schema = session_state.schema_for_ref(table_name.clone())?;ifletSome(provider) = schema.table(name).await? {let input_exec = children.one()?;
provider
.insert_into(session_state, input_exec,false).await?
}else{returnexec_err!("Table '{table_name}' does not exist");}}Instead, I think we should provider
Not sure if this idea works over all the places 🤔 |
alamb
commented
Jul 20, 2024
I plan to check this PR out carefully tomorrow |
TableProvider::scan to take a trait rather than SessionStateThere was a problem hiding this comment.
Thank you @findepi and @jayzhan211
I think this API is quite clever and solves a long standing problem (circular dependency between Catalog -> TableProvider -> SessionState). Like many elegant solutions, once you see it the design is obvious but it was not before seeing.
I also think this API makes the usecase described in #11193 from @cisaacson (providing the same SessionState information via more APIs) straightforward.
I think using a trait (rather than a struct) to break the dependency follows the same pattern used elsewhere in DataFusion (e.g. ScalarUdfImpl)
Next Steps
First I would like to hear what @jayzhan211 thinks
If he thinks we should proceed, since this PR proposes to change a very widely used API in DataFusion I think some extra communication is warranted before we merge:
- mark this PR as
api-changeand change the title to higlight the change toTableProvider - communicate this proposal over the mailing list / slack / discord to maximize the chance anyone with feedback to share has a chance to
- Make sure it is left open for several days for feedback
- Test this change with some downstream users (e.g. I can test this with InfluxDB 3.0 and see if the migration to the new API goes smoothly
Uh oh!
There was an error while loading. Please reload this page.
| /// to return as a final result. | ||
| async fn scan( | ||
| &self, | ||
| state: &dyn CatalogSession, |
There was a problem hiding this comment.
This one line I think is the biggest potential change in this PR as it will require changing all existing TableProviders which is one of the oldest and most widely used APIs in DataFusion
If we are ok with this change, I think the rest of this PR is wonderful
There was a problem hiding this comment.
I checked in the Spice AI codebase, and this will be a relatively minor refactoring for us. I am ok with this change 👍
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Yes I agree with this
I also think this sounds like a reasonable plan - and I think it becomes easier as we split the logic out and defined the API via traits |
alamb
commented
Jul 20, 2024
BTW I agree with most of @jayzhan211 's ideas above, but in my mind they are follow ons / orthogonal to moving the catalog traits out of the core (as in we can do both!) |
Uh oh!
There was an error while loading. Please reload this page.
alamb
commented
Jul 24, 2024
I am feeling even better about this PR. I propose we plan to merge it in 2 days time (Friday) unless there are objections or other comments to address. Thank you @findepi@Omega359@cisaacson@jayzhan211 and @phillipleblanc for your help so far |
alamb
commented
Jul 24, 2024
I slightly prefer However, I don't feel super strongly and would be interested in opinions from others if we want to have a |
findepi
commented
Jul 24, 2024
re: SessionProvider i can change, this is not a big deal. @alamb@jayzhan211@cisaacson@phillipleblanc@Omega359 let's just make sure we have agreement to avoid unnecessary back and forth. |
alamb
commented
Jul 24, 2024
Oh no, I broke the doc test -- sorry @findepi |
alamb
commented
Jul 25, 2024
64e6c20 to
9210b48Comparefindepi
commented
Jul 25, 2024
rebased on current main, no other changes |
alamb
commented
Jul 25, 2024
I think the failure is due to new rust version (if you run Not related to the changes in this PR |
findepi
commented
Jul 25, 2024
it's now fixed and the build is green, but there is a new conflict. will rebase |
This moves `CatalogProvider`, `TableProvider`, `SchemaProvider` to a new `datafusion-catalog` crate. The circular dependency between core `SessionState` and implementations is broken up by introducing `CatalogSession` dyn trait. Implementations of `TableProvider` that reside under core current have access to `CatalogSession` by downcasting. This is supposed to be an intermediate step.
a4d282a to
dbb8905Comparefindepi
commented
Jul 25, 2024
( squashed and rebased, no other changes ) |
alamb
commented
Jul 26, 2024
Let's do it. go go go 🚀 Thanks again everryone for your comments and help. I think this PR finally breaks open the path to separate out the last monolithic knot |
findepi
commented
Jul 26, 2024
🎉 thanks for all the review feedback and the merge! |
berkaysynnada
commented
Aug 2, 2024
Are we tracking this TODO? |
findepi
commented
Aug 2, 2024
@berkaysynnada yes, #11600 |
alamb
commented
Aug 2, 2024
I suggest adding a comment in the code with the link to the ticket to help others find this ticket |
findepi
commented
Aug 2, 2024
good idea! #11784 |
Catlog API was extracted to a separate crate. Ref: apache/datafusion#11516
phillipleblanc
commented
Aug 14, 2024
Looks like this PR didn't get tagged with |
alamb
commented
Aug 14, 2024
Sorry -- thanks for the heads up @phillipleblanc |
Catlog API was extracted to a separate crate. Ref: apache/datafusion#11516
* update datafusion deps to point to githuc.com/apache/datafusion Datafusion 41 is not yet released on crates.io. * update TableProvider::scan Ref: apache/datafusion#11516 * use SessionStateBuilder The old constructor is deprecated. Ref: apache/datafusion#11403 * update AggregateFunction Upstream Changes: - The field name was switched from `func_name` to func. - AggregateFunctionDefinition was removed Ref: apache/datafusion#11803 * update imports in catalog Catlog API was extracted to a separate crate. Ref: apache/datafusion#11516 * use appropriate path for approx_distinct Ref: apache/datafusion#11644 * migrate AggregateExt to ExprFunctionExt Also removed `sqlparser` dependency since it's re-exported upstream. Ref: apache/datafusion#11550 * update regr_count tests for new return type Ref: apache/datafusion#11731 * migrate from function-array to functions-nested The package was renamed upstream. Ref: apache/datafusion#11602 * cargo fmt * lock datafusion deps to 41 * remove todo from cargo.toml All the datafusion dependencies are re-exported, but I still need to figure out *why*.
This moves
CatalogProvider,TableProvider,SchemaProviderto a newdatafusion-catalogcrate. The circular dependency between coreSessionStateand implementations is broken up by introducingCatalogSessiondyn trait. Implementations ofTableProviderthat reside under core current have access toCatalogSessionby downcasting. This is supposed to be an intermediate step.Part of #10782
Relates to #11420