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

[Merged by Bors] - Fix Events::<drain/clear> bug #2206

Closed

Conversation

NathanSWard
Copy link
Contributor

@NathanSWard NathanSWard commented May 18, 2021

Taken from #2145

On draining and clearing, dangling EventReaders would not read into the correct event offset.

@NathanSWard NathanSWard added C-Bug An unexpected or incorrect behavior A-ECS Entities, components, systems, and events labels May 18, 2021
@alice-i-cecile
Copy link
Member

Thanks! This is a nice thing to pull over.

@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label May 18, 2021
@cart
Copy link
Member

cart commented May 18, 2021

Good call. Looks like events.clear() also needs to reset its counters. I'll put together a follow up.

@cart
Copy link
Member

cart commented May 18, 2021

bors r+

bors bot pushed a commit that referenced this pull request May 18, 2021
Taken from #2145

On draining, `Events` did not reset it's internal event count members.
@cart
Copy link
Member

cart commented May 18, 2021

bors r-

@bors
Copy link
Contributor

bors bot commented May 18, 2021

Canceled.

@cart
Copy link
Member

cart commented May 18, 2021

Hmm one issue to discuss that I discovered when putting together my followup:

Resetting event_count means that existing event readers will skip over newly sent events? The test looks like it should fail, so I need to understand why it works before merging :)

@cart
Copy link
Member

cart commented May 18, 2021

image

@NathanSWard
Copy link
Contributor Author

NathanSWard commented May 18, 2021

Good call. Looks like events.clear() also needs to reset its counters. I'll put together a follow up.

@cart I'll add this fix to the PR as well.

Resetting event_count means that existing event readers will skip over newly sent events? The test looks like it should fail, so I need to understand why it works before merging :)

Hmm yes this does seem to be incorrect...
Looks like we might need to add a dirty_flag or something of the sort.

@cart
Copy link
Member

cart commented May 18, 2021

This makes the test above pass, but it feels like I'm missing a corner case:
image

@NathanSWard
Copy link
Contributor Author

NathanSWard commented May 18, 2021

Yep adding this:

        events.send(E(1));
        let _ = events.drain();
        assert_eq!(reader.iter(&events).next(), None);

in the tests causes it to fail.

@cart
Copy link
Member

cart commented May 18, 2021

Yep adding this:

Is that with or without the "fix" above? Adding that passes with the fix for me.

@NathanSWard
Copy link
Contributor Author

@cart, a possible solution:
we might need to add a version field to Events and Event<Reader/Writer> and on calling clear/drain, update the version. So when the Reader/Writer calls .iter() check the versions and reset the Reader/Writer's internal count to 0 if the version has changed.

@NathanSWard
Copy link
Contributor Author

Is that with or without the "fix" above? Adding that passes with the fix for me.

With your change included.
here is the full test i have:

#[test]
    fn test_events_drain() {
        #[derive(PartialEq, Eq, Debug)]
        struct E(usize);

        let mut events = Events::<E>::default();
        let mut reader = events.get_reader();

        assert!(reader.iter(&events).next().is_none());

        events.send(E(0));
        assert_eq!(reader.iter(&events).next(), Some(&E(0)));
        assert_eq!(reader.iter(&events).next(), None);

        events.send(E(1));
        let _ = events.drain();
        assert_eq!(reader.iter(&events).next(), None);

        events.send(E(2));
        events.send(E(3));
        assert_eq!(reader.iter(&events).next(), Some(&E(2)));
        assert_eq!(reader.iter(&events).next(), Some(&E(3)));
        assert_eq!(reader.iter(&events).next(), None);
    }

@cart
Copy link
Member

cart commented May 18, 2021

Found another corner case. Adding an events.update() breaks it.

#[test]
fn test_events_drain() {
    #[derive(PartialEq, Eq, Debug)]
    struct E(usize);
    let mut events = Events::<E>::default();
    let mut reader = events.get_reader();

    assert!(reader.iter(&events).next().is_none());

    events.send(E(0));
    assert_eq!(*reader.iter(&events).next().unwrap(), E(0));
    assert_eq!(reader.iter(&events).next(), None);

    let _ = events.drain();
    assert!(reader.iter(&events).next().is_none());

    events.send(E(1));
    events.update();
    events.send(E(2));
    assert_eq!(*reader.iter(&events).next().unwrap(), E(1));
    assert_eq!(*reader.iter(&events).next().unwrap(), E(2));
}

@cart
Copy link
Member

cart commented May 18, 2021

I'm gonna keep working through my PR review queue. If you find a fix definitely do it for clear() too 😄

I'll check back in later / help out if it hasn't been sorted out yet.

@NathanSWard
Copy link
Contributor Author

NathanSWard commented May 18, 2021

@cart it turns out our last #[test]s are actually invalid... haha 😅

reader.iter(&events) returns an iterator over all events.
We were calling it multiple times expecting it to return a single value.

This is how the test should be structured...

#[test]
    fn test_events_drain() {
        // test stuff

        events.send(E(1));
        events.update();
        events.send(E(2));

        let mut iter = reader.iter(&events);
        assert_eq!(*iter.next().unwrap(), E(1));
        assert_eq!(*iter.next().unwrap(), E(2));
    }

@cart
Copy link
Member

cart commented May 18, 2021

Bahaha whoops. Nice catch!

@NathanSWard NathanSWard changed the title Fix Events::drain bug Fix Events::<drain/clear> bug May 18, 2021
Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

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

Good; factoring out that logic reduces the risk of bugs in the future.

@NathanSWard
Copy link
Contributor Author

@cart I have this current implementation which passed the failing test we set up.
I'm currently toying around with other potential failing tests, and please let me know if you can think of any :)

crates/bevy_ecs/src/event.rs Outdated Show resolved Hide resolved
@cart
Copy link
Member

cart commented May 19, 2021

bors r+

bors bot pushed a commit that referenced this pull request May 19, 2021
Taken from #2145

On draining and clearing, dangling `EventReaders` would not read into the correct event offset.
@bors bors bot changed the title Fix Events::<drain/clear> bug [Merged by Bors] - Fix Events::<drain/clear> bug May 19, 2021
@bors bors bot closed this May 19, 2021
ostwilkens pushed a commit to ostwilkens/bevy that referenced this pull request Jul 27, 2021
Taken from bevyengine#2145

On draining and clearing, dangling `EventReaders` would not read into the correct event offset.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Bug An unexpected or incorrect behavior S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants