-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Fix soudness issue with Conflicts involving read_all
and write_all
#14579
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
Fix soudness issue with Conflicts involving read_all
and write_all
#14579
Conversation
AccessConflict::All => { | ||
// there is no specific component conflicting, but the systems are overall incompatible | ||
// for example 2 systems with `Query<EntityMut>` | ||
conflicting_systems.push((a, b, Vec::new())); |
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.
this is not ideal.. maybe we'd like to introduce a similar enum in the schedule graph conflicts? not sure if that's what we want
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.
IMO this can wait until follow-up.
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.
Out of curiousity, what happens with the ambiguity reporting in this case?
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.
It says that the two systems are ambiguous and conflict on World
: https://github.com/cBournhonesque/bevy/blob/944cc182d2265df2165ac03372d681d718e1723d/crates/bevy_ecs/src/schedule/schedule.rs#L1883-L1883
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.
I'm in favor of newtyping the conflicts here: more flexible and clearer.
This has tests for both the query and the system case which is great, but I'd also like to see EntityRef
+ EntityMut
, and EntityMut
+ &World
tested.
crates/bevy_ecs/src/query/access.rs
Outdated
let mut conflicts = FixedBitSet::new(); | ||
if self.reads_all { | ||
// QUESTION: How to handle `other.writes_all`? | ||
if other.writes_all { |
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.
this is the key change
crates/bevy_ecs/src/query/access.rs
Outdated
|
||
/// Returns a vector of elements that this and `other` cannot access at the same time. | ||
pub fn get_conflicts(&self, other: &FilteredAccess<T>) -> Vec<T> { | ||
pub fn get_conflicts(&self, other: &FilteredAccess<T>) -> AccessConflict { |
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.
This is technically breaking, but I don't think it's worth refactoring to avoid this.
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.
my general opinion is that fixing unsoundness takes priority over semver. there are of course ways to avoid both in the same release but getting the soundness fix out as quickly as possible is important imo.
It looks like your PR is a breaking change, but you didn't provide a migration guide. Could you add some context on what users should update when this change get released in a new version of Bevy? |
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.
definitely a solid soundness fix; a couple of nits which can easily wait until a followup!
I like these little suggestions: let me know if you want to do them now or in a follow-up :) |
They make sense to me; I applied them now! |
@cBournhonesque let me know when the conflicts are resolved. I was pretty sure this would happen 😂 |
Indeed! Updated :) |
if self.reads_all_resources { | ||
// QUESTION: How to handle `other.writes_all`? | ||
if other.reads_all_resources { | ||
return AccessConflicts::All; | ||
} | ||
conflicts.extend(other.resource_writes.ones()); | ||
} | ||
|
||
if other.reads_all_resources { | ||
// QUESTION: How to handle `self.writes_all`. | ||
if self.reads_all_resources { | ||
return AccessConflicts::All; | ||
} | ||
conflicts.extend(self.resource_writes.ones()); |
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.
These two new inner if
s should check for writes_all_resources
and not reads_all_resources
.
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.
oh you'r right, that's a bug..
We don't have a unit test for this because there's nothing that queries all resources but not all components
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.
Should we remove the AccessConflicts::ALL
conflicts for resources entirely?
# Objective - I made a mistake when fixing the merge conflicts here: #14579 (comment) It wasn't caught because there's no easy way to trigger access conflicts with resources without triggering them with components first.
Objective
conflicts()
to check for system ambiguities + soundness issues. However since the current conflicts is aVec<T>
, we cannot express conflicts where there is no specificComponentId
at fault. For exampleq1: Query<EntityMut>, q2: Query<EntityMut>
There was a TODO to handle the
write_all
case but it was never resolvedSolution
AccessConflict
enum that is either a list of specific ids that are conflicting orAll
if all component ids are conflictingTesting
EntityMut
caseMigration guide
The
get_conflicts
method ofAccess
now returns anAccessConflict
enum instead of simply aVec
ofComponentId
s that are causing the access conflict. This can be useful in cases where there are no particularComponentId
s conflicting, but instead all of them are; for examplefn system(q1: Query<EntityMut>, q2: Query<EntityRef>)