Skip to content
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] Support cache ListFiles result cache in session level #7620

Merged
merged 11 commits into from
Oct 7, 2023

Conversation

Ted-Jiang
Copy link
Member

Which issue does this PR close?

Closes #7618.

Rationale for this change

What changes are included in this PR?

Are these changes tested?

Are there any user-facing changes?

@github-actions github-actions bot added the core Core DataFusion crate label Sep 22, 2023
opt: &ListingOptions,
) -> ListingTable {
let schema = opt.infer_schema(state1, table_path).await.unwrap();
let schema = opt
.infer_schema(&SessionState::default(), table_path)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here infer_schema will call list_files as well, so create a new Session state here

@@ -94,9 +94,69 @@ impl CacheAccessor<Path, Arc<Statistics>> for DefaultFileStatisticsCache {
}
}

/// Collected files metadata for listing files.
/// Cache will not invalided until user call remove or clear.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here keep simple, user can use their own notify system to decide call remove or clear

Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me @Ted-Jiang -- thank you. The only thing I think needs to be addressed prior to merge is the addition of SessionState::default

@@ -1405,6 +1405,15 @@ pub fn default_session_builder(config: SessionConfig) -> SessionState {
SessionState::with_config_rt(config, Arc::new(RuntimeEnv::default()))
}

impl Default for SessionState {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am worried that providing a Default for SessionState might allow subtle bugs, specifically accidentally running queries or other operations without properly threading through the configuration or runtime. I believe that is why there is no SessionState::new() or Default

🤔 this context would be nice to add as a comment to SessonState

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it there are many options to set in SessionState , i just want to write less code when construct SessionState see there are already default in SessionConfig and RuntimeEnv 😂 , it make sense let user point what conf they want.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should remove the Default impl and instead have a function for tests (test_session_state() or similar) to avoid misuse of this API.

Here is a PR to add some comments about the rationale for not having a Default impl: #7654

datafusion/execution/src/cache/cache_unit.rs Show resolved Hide resolved
datafusion/execution/src/cache/cache_manager.rs Outdated Show resolved Hide resolved
@alamb
Copy link
Contributor

alamb commented Sep 23, 2023

I was thinking a little about the cache APIs here -- at the moment these are all related to ListingTable but are attached to the SessionState. I wonder if we should make a containing structure like ListingTableCache or something to contain them 🤔 .

This is not a suggested change for this PR, just something I was thinking about.

@Ted-Jiang
Copy link
Member Author

Ted-Jiang commented Sep 24, 2023

I was thinking a little about the cache APIs here -- at the moment these are all related to ListingTable but are attached to the SessionState. I wonder if we should make a containing structure like ListingTableCache or something to contain them 🤔 .

This is not a suggested change for this PR, just something I was thinking about.

Thanks for your kindly review @alamb ! Yes the cache method here are all in ListingTable, I will check refine it later.

As this is cache , it need share the cache result in some place, i think there is only SessionState has the state can share in some level like(session), is there any other way to store the result ?

btw i see other system use global value to store global cache, is there a way datafusion use this method

@alamb
Copy link
Contributor

alamb commented Sep 25, 2023

btw i see other system use global value to store global cache, is there a way datafusion use this method

The way IOx does this is to setup a RuntimeConfig with a global MemoryManager and DiskManager and then create SessionContext's from that RuntimeConfig.

I think you can do something similar with the caches in this PR

@suremarc
Copy link
Contributor

Are there any advantages to caching file listing in DataFusion instead of inside the ObjectStore? It seems to me it should be possible to implement this without any changes to DataFusion itself. There may be tradeoffs there I'm not aware of though

Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Ted-Jiang -- I think we should remove the Default impl for SessionState from this PR

@@ -1405,6 +1405,15 @@ pub fn default_session_builder(config: SessionConfig) -> SessionState {
SessionState::with_config_rt(config, Arc::new(RuntimeEnv::default()))
}

impl Default for SessionState {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should remove the Default impl and instead have a function for tests (test_session_state() or similar) to avoid misuse of this API.

Here is a PR to add some comments about the rationale for not having a Default impl: #7654

@alamb
Copy link
Contributor

alamb commented Sep 25, 2023

Are there any advantages to caching file listing in DataFusion instead of inside the ObjectStore? It seems to me it should be possible to implement this without any changes to DataFusion itself. There may be tradeoffs there I'm not aware of though

This is an excellent point @suremarc -- what do you think @Ted-Jiang of making a Caching ObjectStore implementation? As @suremarc points out, there is nothing DataFusion specific about this feature, so perhaps it would be better modeled at the ObjectStore level 🤔

@alamb alamb marked this pull request as draft September 28, 2023 16:56
@alamb
Copy link
Contributor

alamb commented Sep 28, 2023

Converting to draft as it is not waiting on a review -- we are now working through comments

Arc::new(memory)
(
Arc::new(memory),
SessionState::with_config_rt(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the default of SeesionState

@Ted-Jiang
Copy link
Member Author

Ted-Jiang commented Oct 3, 2023

@alamb @suremarc Sorry for the delay.

making a Caching ObjectStore implementation?

As i have check the some remote store client like hdfs there are no cache result in client side, IMO doing this is ObjectStore may be difficult define the work scope (ensure correctness), in datafusion we can support in in session level to not effect others 🤔

@Ted-Jiang Ted-Jiang marked this pull request as ready for review October 3, 2023 04:20
@Ted-Jiang Ted-Jiang requested a review from alamb October 3, 2023 10:53
@Ted-Jiang
Copy link
Member Author

@alamb could you take a look plz

@suremarc
Copy link
Contributor

suremarc commented Oct 6, 2023

@alamb @suremarc Sorry for the delay.

making a Caching ObjectStore implementation?

As i have check the some remote store client like hdfs there are no cache result in client side, IMO doing this is ObjectStore may be difficult define the work scope (ensure correctness), in datafusion we can support in in session level to not effect others 🤔

I agree it would be more difficult, having implemented some caching of my own recently. A full implementation would require dealing with invalidation/consistency, particularly for update operations, as well as supporting nontrivial APIs like list_with_delimiter. It would be nice if we could do it there but it's unclear to me if it can be done perfectly.

On that note, I'd like to point out that this cache implementation won't avoid hitting object storage if your table has partition columns, because in that case DataFusion will instead call list_with_delimiter recursively, starting from the top-level path. It would still be an improvement, but I am not sure if this will speed up query planning as much as you want. Just wanted to make sure you're aware of this, as I previously had thought that simply caching list_all_files would avoid hitting object storage altogether.

Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Ted-Jiang and @suremarc

Do you have any performance measurements you can shar @Ted-Jiang about how much this feature increases performance for your usecase?

datafusion/execution/src/cache/cache_manager.rs Outdated Show resolved Hide resolved
@Ted-Jiang
Copy link
Member Author

Ted-Jiang commented Oct 7, 2023

Thanks @Ted-Jiang and @suremarc

Do you have any performance measurements you can shar @Ted-Jiang about how much this feature increases performance for your usecase?

We try to fix the situation when calling remote storage list file statistics sometimes are not stable:
we run one query avg cost 4 seconds, but sometimes it cost double time, we print some log for debug:

2023-09-12T06:10:59.098033Z  INFO tokio-runtime-worker ThreadId(16) datafusion::execution::context: Datafusion optimize logical plan cost: 10.852243ms
2023-09-12T06:11:03.309479Z  INFO tokio-runtime-worker ThreadId(16) datafusion::execution::context: Datafusion create physical plan cost: **_4.2222994s_**
2023-09-12T06:11:03.309543Z  INFO tokio-runtime-worker ThreadId(16) ballista_scheduler::planner: planning query stages for job VyQVhat
2023-09-12T06:11:06.439247Z  INFO tokio-runtime-worker ThreadId(20) ballista_scheduler::display: === [VyQVhat/1] Stage finished, physical plan with metrics ===

we saw half time cost in create physical plan 🤣 (btw we pass logic plan LIST_TABLE to datafusion in out front end (written in JAVA))

after enable cache we fix this problem the query time keep stable.

btw we have fix the consistency in our java side, because out sys build kind of materialized view, if we we change the source data the path as the cache key also change.

I'd like to point out that this cache implementation won't avoid hitting object storage if your table has partition columns, because in that case DataFusion will instead call list_with_delimiter recursively

@suremarc thanks for point this out 👍 i will figure out this later.

@github-actions github-actions bot added sql SQL Planner logical-expr Logical plan and expressions physical-expr Physical Expressions optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt) substrait labels Oct 7, 2023
@github-actions github-actions bot removed sql SQL Planner logical-expr Logical plan and expressions physical-expr Physical Expressions optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt) substrait labels Oct 7, 2023
@alamb alamb merged commit 093b775 into apache:main Oct 7, 2023
22 checks passed
@alamb
Copy link
Contributor

alamb commented Oct 7, 2023

Thanks again @Ted-Jiang and @suremarc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Core DataFusion crate
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Cache] Support cache ListFiles result cache in session level
3 participants