feat(sdk): Remove EventCacheStore, TimelineEntry, RoomInfo and MemoryStore.

This commit is contained in:
Ivan Enderlin
2024-03-18 15:17:25 +01:00
parent 5bb2511914
commit 85538dc3ed
2 changed files with 16 additions and 202 deletions

View File

@@ -70,7 +70,7 @@ use tracing::{error, instrument, trace, warn};
use self::{
linked_chunk::ChunkContent,
store::{EventCacheStore, Gap, MemoryStore, PaginationToken, RoomEvents, TimelineEntry},
store::{Gap, PaginationToken, RoomEvents},
};
use crate::{client::ClientInner, room::MessagesOptions, Client, Room};
@@ -767,7 +767,7 @@ mod tests {
use matrix_sdk_test::{async_test, sync_timeline_event};
use ruma::room_id;
use super::{store::TimelineEntry, EventCacheError};
use super::EventCacheError;
use crate::{event_cache::store::PaginationToken, test_utils::logged_in_client};
#[async_test]

View File

@@ -12,199 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::{collections::BTreeMap, fmt, iter::once, result::Result as StdResult};
use std::{fmt, iter::once, result::Result};
use async_trait::async_trait;
use matrix_sdk_common::deserialized_responses::SyncTimelineEvent;
use ruma::{OwnedRoomId, RoomId};
use tokio::sync::RwLock;
use super::{
linked_chunk::{
Chunk, ChunkIdentifier, LinkedChunk, LinkedChunkError, LinkedChunkIter,
LinkedChunkIterBackward, Position,
},
Result,
use super::linked_chunk::{
Chunk, ChunkIdentifier, LinkedChunk, LinkedChunkError, LinkedChunkIter,
LinkedChunkIterBackward, Position,
};
/// A store that can be remember information about the event cache.
///
/// It really acts as a cache, in the sense that clearing the backing data
/// should not have any irremediable effect, other than providing a lesser user
/// experience.
#[async_trait]
pub trait EventCacheStore: Send + Sync {
/// Returns all the known events for the given room.
async fn room_events(&self, room: &RoomId) -> Result<Vec<SyncTimelineEvent>>;
/// Adds all the entries to the given room's timeline.
async fn append_room_entries(&self, room: &RoomId, entries: Vec<TimelineEntry>) -> Result<()>;
/// Returns whether the store knows about the given pagination token.
async fn contains_gap(&self, room: &RoomId, pagination_token: &PaginationToken)
-> Result<bool>;
/// Replaces a given gap (identified by its pagination token) with the given
/// entries.
///
/// Note: if the gap hasn't been found, then nothing happens, and the events
/// are lost.
///
/// Returns whether the gap was found.
async fn replace_gap(
&self,
room: &RoomId,
gap_id: Option<&PaginationToken>,
entries: Vec<TimelineEntry>,
) -> Result<bool>;
/// Retrieve the oldest backpagination token for the given room.
async fn oldest_backpagination_token(&self, room: &RoomId) -> Result<Option<PaginationToken>>;
/// Clear all the information tied to a given room.
///
/// This forgets the following:
/// - events in the room
/// - pagination tokens
async fn clear_room(&self, room: &RoomId) -> Result<()>;
}
/// A newtype wrapper for a pagination token returned by a /messages response.
#[derive(Clone, Debug, PartialEq)]
pub struct PaginationToken(pub String);
#[derive(Clone)]
pub enum TimelineEntry {
Event(SyncTimelineEvent),
Gap {
/// The token to use in the query, extracted from a previous "from" /
/// "end" field of a `/messages` response.
prev_token: PaginationToken,
},
}
/// All the information related to a room and stored in the event cache.
#[derive(Default)]
struct RoomInfo {
/// All the timeline entries per room, in sync order.
entries: Vec<TimelineEntry>,
}
impl RoomInfo {
fn clear(&mut self) {
self.entries.clear();
}
}
/// An [`EventCacheStore`] implementation that keeps all the information in
/// memory.
#[derive(Default)]
pub(crate) struct MemoryStore {
by_room: RwLock<BTreeMap<OwnedRoomId, RoomInfo>>,
}
impl MemoryStore {
/// Create a new empty [`MemoryStore`].
pub fn new() -> Self {
Default::default()
}
}
#[async_trait]
impl EventCacheStore for MemoryStore {
async fn room_events(&self, room: &RoomId) -> Result<Vec<SyncTimelineEvent>> {
Ok(self
.by_room
.read()
.await
.get(room)
.map(|room_info| {
room_info
.entries
.iter()
.filter_map(
|entry| if let TimelineEntry::Event(ev) = entry { Some(ev) } else { None },
)
.cloned()
.collect()
})
.unwrap_or_default())
}
async fn append_room_entries(&self, room: &RoomId, entries: Vec<TimelineEntry>) -> Result<()> {
self.by_room.write().await.entry(room.to_owned()).or_default().entries.extend(entries);
Ok(())
}
async fn clear_room(&self, room: &RoomId) -> Result<()> {
// Clear the room, so as to avoid reallocations if the room is being reused.
// XXX: do we also want an actual way to *remove* a room? (for left rooms)
if let Some(room) = self.by_room.write().await.get_mut(room) {
room.clear();
}
Ok(())
}
async fn oldest_backpagination_token(&self, room: &RoomId) -> Result<Option<PaginationToken>> {
Ok(self.by_room.read().await.get(room).and_then(|room| {
room.entries.iter().find_map(|entry| {
if let TimelineEntry::Gap { prev_token: backpagination_token } = entry {
Some(backpagination_token.clone())
} else {
None
}
})
}))
}
async fn contains_gap(&self, room: &RoomId, needle: &PaginationToken) -> Result<bool> {
let mut by_room_guard = self.by_room.write().await;
let room = by_room_guard.entry(room.to_owned()).or_default();
Ok(room.entries.iter().any(|entry| {
if let TimelineEntry::Gap { prev_token: existing } = entry {
existing == needle
} else {
false
}
}))
}
async fn replace_gap(
&self,
room: &RoomId,
token: Option<&PaginationToken>,
entries: Vec<TimelineEntry>,
) -> Result<bool> {
let mut by_room_guard = self.by_room.write().await;
let room = by_room_guard.entry(room.to_owned()).or_default();
if let Some(token) = token {
let gap_pos = room.entries.iter().enumerate().find_map(|(i, t)| {
if let TimelineEntry::Gap { prev_token: existing } = t {
if existing == token {
return Some(i);
}
}
None
});
if let Some(pos) = gap_pos {
room.entries.splice(pos..pos + 1, entries);
Ok(true)
} else {
Ok(false)
}
} else {
// We had no previous token: assume we can prepend the events.
room.entries.splice(0..0, entries);
Ok(true)
}
}
}
#[derive(Debug)]
pub struct Gap {
/// The token to use in the query, extracted from a previous "from" /
@@ -266,7 +86,7 @@ impl RoomEvents {
&mut self,
events: I,
position: Position,
) -> StdResult<(), LinkedChunkError>
) -> Result<(), LinkedChunkError>
where
I: IntoIterator<Item = SyncTimelineEvent>,
I::IntoIter: ExactSizeIterator,
@@ -275,11 +95,7 @@ impl RoomEvents {
}
/// Insert a gap at a specified position.
pub fn insert_gap_at(
&mut self,
gap: Gap,
position: Position,
) -> StdResult<(), LinkedChunkError> {
pub fn insert_gap_at(&mut self, gap: Gap, position: Position) -> Result<(), LinkedChunkError> {
self.chunks.insert_gap_at(gap, position)
}
@@ -291,7 +107,7 @@ impl RoomEvents {
&mut self,
items: I,
gap_identifier: ChunkIdentifier,
) -> StdResult<(), LinkedChunkError>
) -> Result<(), LinkedChunkError>
where
I: IntoIterator<Item = SyncTimelineEvent>,
I::IntoIter: ExactSizeIterator,
@@ -335,7 +151,7 @@ impl RoomEvents {
pub fn rchunks_from(
&self,
identifier: ChunkIdentifier,
) -> StdResult<
) -> Result<
LinkedChunkIterBackward<'_, SyncTimelineEvent, Gap, DEFAULT_CHUNK_CAPACITY>,
LinkedChunkError,
> {
@@ -347,10 +163,8 @@ impl RoomEvents {
pub fn chunks_from(
&self,
identifier: ChunkIdentifier,
) -> StdResult<
LinkedChunkIter<'_, SyncTimelineEvent, Gap, DEFAULT_CHUNK_CAPACITY>,
LinkedChunkError,
> {
) -> Result<LinkedChunkIter<'_, SyncTimelineEvent, Gap, DEFAULT_CHUNK_CAPACITY>, LinkedChunkError>
{
self.chunks.chunks_from(identifier)
}
@@ -364,7 +178,7 @@ impl RoomEvents {
/// Iterate over the events, forward.
///
/// The oldest event comes first.
pub fn events(&self) -> impl Iterator<Item = (ItemPosition, &SyncTimelineEvent)> {
pub fn events(&self) -> impl Iterator<Item = (Position, &SyncTimelineEvent)> {
self.chunks.items()
}
@@ -372,7 +186,7 @@ impl RoomEvents {
pub fn revents_from(
&self,
position: Position,
) -> StdResult<impl Iterator<Item = (Position, &SyncTimelineEvent)>, LinkedChunkError> {
) -> Result<impl Iterator<Item = (Position, &SyncTimelineEvent)>, LinkedChunkError> {
self.chunks.ritems_from(position)
}
@@ -381,13 +195,13 @@ impl RoomEvents {
pub fn events_from(
&self,
position: Position,
) -> StdResult<impl Iterator<Item = (Position, &SyncTimelineEvent)>, LinkedChunkError> {
) -> Result<impl Iterator<Item = (Position, &SyncTimelineEvent)>, LinkedChunkError> {
self.chunks.items_from(position)
}
}
impl fmt::Debug for RoomEvents {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> StdResult<(), fmt::Error> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
formatter.debug_struct("RoomEvents").field("chunk", &self.chunks).finish()
}
}