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

Fix indexing issue in ObservableMap #4346

Merged
merged 3 commits into from
Dec 2, 2024

Conversation

gferon
Copy link
Contributor

@gferon gferon commented Nov 28, 2024

The client we're building is panicking on startups in some random cases with the following error message Value should be present or has just been inserted, but it's missing. There seems to be a pretty serious bug in observable_map.rs which I initially demonstrated with an extension of the existing unit tests in 6d6f8e4.

Any .remove operation called on a ObservableMap will not re-index values after the removed position, which means any later operation on elements inserted after the previously removed key will either be fetched wrongly, or panic when using .get_or_create.

This PR fixes these two related bugs and adds extra test cases.

@gferon gferon marked this pull request as ready for review November 28, 2024 11:43
@gferon gferon requested a review from a team as a code owner November 28, 2024 11:43
@gferon gferon requested review from poljar and removed request for a team November 28, 2024 11:43
@bnjbvr
Copy link
Member

bnjbvr commented Nov 28, 2024

Duh, great catch, not sure how we've missed that.

@gferon
Copy link
Contributor Author

gferon commented Nov 28, 2024

Do you want me to come up with a fix? I'd gladly spend some time doing that.

@bnjbvr
Copy link
Member

bnjbvr commented Nov 28, 2024

Absolutely, thanks!

@gferon gferon changed the title Add more test cases to ObservableMap to demonstrate indexing issue Fix indexing issue in ObservableMap Nov 28, 2024
@gferon gferon force-pushed the observable-map-panic-bug-repro branch from 37d748a to f5443c5 Compare November 28, 2024 13:29
Copy link
Member

@bnjbvr bnjbvr left a comment

Choose a reason for hiding this comment

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

Can we do a swap-remove and only update the position of the swapped value?

@gferon
Copy link
Contributor Author

gferon commented Nov 28, 2024

@bnjbvr just gave it a shot, the extra test cases now pass.

This is a trade-off. This implementation is simple enough for the moment, and basically does the job

It's obviously not the best possible solution in terms of complexity, but I think it fulfills the criteria defined in the code comment quoted above. 😄

@gferon gferon force-pushed the observable-map-panic-bug-repro branch from f5443c5 to 9bfaf81 Compare November 28, 2024 13:33
Copy link

codecov bot commented Nov 28, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 85.00%. Comparing base (0b16d48) to head (200f20d).
Report is 111 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4346      +/-   ##
==========================================
- Coverage   85.02%   85.00%   -0.02%     
==========================================
  Files         274      274              
  Lines       30107    30089      -18     
==========================================
- Hits        25599    25578      -21     
- Misses       4508     4511       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@gferon
Copy link
Contributor Author

gferon commented Nov 28, 2024

Can we do a swap-remove and only update the position of the swapped value?

Absolutely better indeed, why didn't I think of that?! You will still have to scan the entire mapping map to find the right value, though.

Unfortunately, there's no ObservableVec::swap_remove - I could do it in two separate function calls though.

@gferon
Copy link
Contributor Author

gferon commented Nov 28, 2024

It looks like I cannot even call self.values.swap on the &mut self ref because of some missing trait bound in eyeball-im (EDIT: found it, it's on purpose "No DerefMut because all mutating must go through inherent methods that notify subscribers"). @bnjbvr I sent you a DM on Matrix, so we can communicate directly.

EDIT: swap_remove doesn't seem to be what we're looking for as it doesn't guarantee the remaining elements order, see https://doc.rust-lang.org/std/vec/struct.Vec.html#method.swap_remove

@bnjbvr bnjbvr requested review from bnjbvr and removed request for poljar December 2, 2024 09:03
@bnjbvr bnjbvr changed the title Fix indexing issue in ObservableMap Fix indexing issue in ObservableMap Dec 2, 2024
Copy link
Member

@bnjbvr bnjbvr left a comment

Choose a reason for hiding this comment

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

Thanks, this is a good bandaid solution, and we can implement something using a manual swap-remove later, if needs be.

@bnjbvr bnjbvr enabled auto-merge (squash) December 2, 2024 15:42
@bnjbvr bnjbvr merged commit ed1d406 into matrix-org:main Dec 2, 2024
39 of 40 checks passed
@Hywan
Copy link
Member

Hywan commented Dec 3, 2024

Thanks for the fix!

@gferon
Copy link
Contributor Author

gferon commented Dec 3, 2024

Thanks for reviewing and merging this quickly. I feel like this fix warrants a 0.8.1 release on crates.io since the indexing issue leads to having get_room return to the wrong room after any call of forget_room (or any operation that deleted a room from the store as a side effect).

@bnjbvr
Copy link
Member

bnjbvr commented Dec 3, 2024

Our plan is to do a release somewhere around the end of the month (Christmas maybe), which will include this fix.

andybalaam pushed a commit that referenced this pull request Dec 18, 2024
Any `.remove` operation called on a `ObservableMap` did not re-index
`values` _after_ the removed position, which means any later operation
on elements inserted after the previously removed key would either be
fetched wrongly, or panic when using `.get_or_create`.

This PR fixes these two related bugs and adds extra test cases.

---------

Signed-off-by: [email protected]
Co-authored-by: Benjamin Bouvier <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants