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

Add two streams to get the timeline of a room and store timeline to SledStore #486

Merged
merged 18 commits into from Feb 23, 2022

Conversation

jsparber
Copy link
Contributor

@jsparber jsparber commented Feb 8, 2022

This is the first part of #288 (comment)

This doesn't yet implement a local cache for messages.

To implement the message cache the store implementation needs to collect the TimelineSlices received via the StateChanges struct. The store then needs to return a stream of events via StateStore::room_timeline().

@jsparber
Copy link
Contributor Author

jsparber commented Feb 8, 2022

I'm not sure how to fix the issue with the matrix-sdk-exmplae-wasm_command_bot example.

@gnunicorn
Copy link
Contributor

@jsparber it appears that the SinkExt you are using is an optional feature of future-util, hidden behind the sink-feature-flag, which we are not activating. I suspect the only reason it works usually is because something else is activating it when we are std. However, the proper fix is to add features = ["sink"] to future-util entry in the Cargo.toml.

@jsparber
Copy link
Contributor Author

jsparber commented Feb 8, 2022

@jsparber it appears that the SinkExt you are using is an optional feature of future-util, hidden behind the sink-feature-flag, which we are not activating. I suspect the only reason it works usually is because something else is activating it when we are std. However, the proper fix is to add features = ["sink"] to future-util entry in the Cargo.toml.

i think i tried that already. And it caused it to fail differently. Let's see what happens.

@jsparber jsparber force-pushed the timeline_stream branch 3 times, most recently from 81c9939 to a6e8fcf Compare February 10, 2022 10:29
@jsparber
Copy link
Contributor Author

@gnunicorn I figured out that we don't even need SinkExt i should have used unbounded_send

@jsparber jsparber force-pushed the timeline_stream branch 2 times, most recently from 7a3a71d to 63bc7ab Compare February 11, 2022 19:15
@jsparber
Copy link
Contributor Author

I now implemented also storing events to the statestore for SledStore. I think this is ready for a review and feedback. Even though I still need to add some tests for it. Right now I tested it with https://gitlab.gnome.org/GNOME/fractal/-/merge_requests/985

@jsparber jsparber force-pushed the timeline_stream branch 3 times, most recently from 19af93e to 76a7d79 Compare February 11, 2022 19:50
@jsparber jsparber changed the title Add two streams to get the timeline of a room Add two streams to get the timeline of a room and store timeline to SledStore Feb 11, 2022
@jsparber jsparber force-pushed the timeline_stream branch 3 times, most recently from 228df67 to 2d98787 Compare February 14, 2022 14:25
@jsparber
Copy link
Contributor Author

I added now also tests :)

@poljar
Copy link
Contributor

poljar commented Feb 15, 2022

Could you please rebase to get rid of the CI error?

@jsparber jsparber force-pushed the timeline_stream branch 3 times, most recently from 1b86797 to b1d1ae8 Compare February 15, 2022 13:19
Copy link
Contributor

@gnunicorn gnunicorn left a comment

Choose a reason for hiding this comment

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

I have a few API and some implementation request.

crates/matrix-sdk-base/src/rooms/normal.rs Outdated Show resolved Hide resolved
crates/matrix-sdk-base/src/rooms/normal.rs Show resolved Hide resolved
crates/matrix-sdk-base/src/store/sled_store.rs Outdated Show resolved Hide resolved
crates/matrix-sdk-base/src/timeline_stream.rs Outdated Show resolved Hide resolved
crates/matrix-sdk/src/client.rs Outdated Show resolved Hide resolved
crates/matrix-sdk-base/src/timeline_stream.rs Outdated Show resolved Hide resolved
crates/matrix-sdk/src/client.rs Outdated Show resolved Hide resolved
crates/matrix-sdk/src/room/common.rs Show resolved Hide resolved
crates/matrix-sdk/src/room/common.rs Show resolved Hide resolved
crates/matrix-sdk-base/src/timeline_stream.rs Outdated Show resolved Hide resolved
crates/matrix-sdk/src/room/common.rs Show resolved Hide resolved
crates/matrix-sdk/src/room/common.rs Outdated Show resolved Hide resolved
crates/matrix-sdk-base/src/timeline_stream.rs Outdated Show resolved Hide resolved
The TimelineSlice is a slice of the timeline of a room and contains the
start and end of the slice.
This writes slices from StateChanges::timeline to the SledStore.
The cache is removed when ever a limited sync response is received or
when an event already known to the store is received.

Stored events are redacted when a redaction event is received.
The test is only run when the `sled_state_store` feature is enabled.
This also changes the test_json::MORE_SYNC and test_json::MORE_SYNC_2 to
not responsed with a limited timeline.
@gnunicorn
Copy link
Contributor

@jsparber please don't force push on PRs (or any published branches for that matter), it makes tracking of changes hard to impossible. Namely, if the branch has been pulled locally, it messes with git and, more annoyingly, the Github Review features can't keep track of the changes, requiring reviewers to not only review the new changes made but the entire PR as a whole again. Thus making it more (annoying) work, that is more error-prone (because changes are easier overlooked) and delaying the process of getting things reviewed and merged.

@jsparber
Copy link
Contributor Author

@jsparber please don't force push on PRs (or any published branches for that matter), it makes tracking of changes hard to impossible. Namely, if the branch has been pulled locally, it messes with git and, more annoyingly, the Github Review features can't keep track of the changes, requiring reviewers to not only review the new changes made but the entire PR as a whole again. Thus making it more (annoying) work, that is more error-prone (because changes are easier overlooked) and delaying the process of getting things reviewed and merged.

Oh sorry, i'm used to that. I think Gitlab handles rebases better, and we do it all the time to keep the commit history clean and it works fairly well. I won't do it here anymore.

@jsparber
Copy link
Contributor Author

@gnunicorn Do you also don't want me to rebase the branch on top of main?

@gnunicorn
Copy link
Contributor

@jsparber just merge main in, this is no problem.

Copy link
Contributor

@gnunicorn gnunicorn left a comment

Choose a reason for hiding this comment

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

minor nitpicks! Thanks heaps!

Comment on lines 613 to 632
if room_version.is_none() {
room_version = Some(room_infos
.get(&room_key)?
.await?
.map(|r| self.deserialize_event::<RoomInfo>(r))
.transpose()?
.and_then(|info| {
info.base_info
.create
.map(|event| event.room_version)
}).unwrap_or_else(|| {
warn!("Unable to find the room version for {}, assume version 9", room_id);
RoomVersionId::V9
}));
}

full_event.event = Raw::new(&AnySyncRoomEvent::from(
inner_event
.redact(redaction, room_version.as_ref().unwrap()),
))?;
Copy link
Contributor

Choose a reason for hiding this comment

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

If we unwrap the room version next anyways, why store it into a Some first? Instead let's do (still needs formatting fixes, but you get the gist):

Suggested change
if room_version.is_none() {
room_version = Some(room_infos
.get(&room_key)?
.await?
.map(|r| self.deserialize_event::<RoomInfo>(r))
.transpose()?
.and_then(|info| {
info.base_info
.create
.map(|event| event.room_version)
}).unwrap_or_else(|| {
warn!("Unable to find the room version for {}, assume version 9", room_id);
RoomVersionId::V9
}));
}
full_event.event = Raw::new(&AnySyncRoomEvent::from(
inner_event
.redact(redaction, room_version.as_ref().unwrap()),
))?;
let room_v = if let Some(room_v) = room_version {
room_v
} else {
room_infos
.get(&room_key)?
.await?
.map(|r| self.deserialize_event::<RoomInfo>(r))
.transpose()?
.and_then(|info| {
info.base_info
.create
.map(|event| event.room_version)
}).unwrap_or_else(|| {
warn!("Unable to find the room version for {}, assume version 9", room_id);
RoomVersionId::V9
}))
};
}
full_event.event = Raw::new(&AnySyncRoomEvent::from(
inner_event
.redact(redaction, room_v),
))?;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the idea is that we only lookup the room version once per TimelineSlice and not for every single event we need to remove.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we could also use OnceCell but i didn't want to introduce a new crate for this single use case.

Copy link
Contributor

@gnunicorn gnunicorn Feb 23, 2022

Choose a reason for hiding this comment

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

Well... but why within the loop though? Am I missing something or isn't everything within that call already available on line 592 and thus should just happen there outside/before the loop? Arguably as it happens in both cases of iteration - even outside of this?

Generally, more than 4 levels of indentation are very hard to read and follow (and makes the lines break more often than necessary), I wonder if we can't just make some of them simpler... and moving the block out would already do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Before we check events we can't be sure if we will need the room version, therefore i look it up only at the first use

if let Some(position) = data.event_id_to_position.get(&redaction.redacts) {
if let Some(mut full_event) = data_events.get_mut(position) {
let inner_event = full_event.event.deserialize()?;
if room_version.is_none() {
Copy link
Contributor

Choose a reason for hiding this comment

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

same as above

crates/matrix-sdk-base/src/store/mod.rs Show resolved Hide resolved
.transpose()?
{
let inner_event = full_event.event.deserialize()?;
if room_version.is_none() {
Copy link
Contributor

Choose a reason for hiding this comment

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

same as above

event_id_to_position_batch.remove(key?)
}

let ret: Result<(), TransactionError<SerializationError>> =
Copy link
Contributor

Choose a reason for hiding this comment

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

why do these have their own transactions and are not bundled together with the other transaction? A transaction failing implies that none of the given data has been submitted, but by splitting this into three functions, if only the last transaction fails, we have an (not terribly) inconsistent database state. Let's move these into the same transaction closure pls

Copy link
Contributor Author

Choose a reason for hiding this comment

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

unfortunately this isn't possible, because of a limitation of sledstore. Since this issue isn't introduced by this MR, i would prefer to handle it separately.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

unfortunately this isn't possible, because of a limitation of sledstore.

Actually, i think it would be. We can uses batches.

@poljar what do you think?

crates/matrix-sdk/src/client.rs Show resolved Hide resolved
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.

None yet

3 participants