parallelize sender edu selection

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-11-29 03:25:29 +00:00
parent 6175e72f1c
commit b5266ad9f5

View file

@ -1,7 +1,7 @@
use std::{ use std::{
cmp,
collections::{BTreeMap, HashMap, HashSet}, collections::{BTreeMap, HashMap, HashSet},
fmt::Debug, fmt::Debug,
sync::atomic::{AtomicU64, AtomicUsize, Ordering},
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@ -13,7 +13,12 @@ use conduit::{
utils::{calculate_hash, math::continue_exponential_backoff_secs, ReadyExt}, utils::{calculate_hash, math::continue_exponential_backoff_secs, ReadyExt},
warn, Error, Result, warn, Error, Result,
}; };
use futures::{future::BoxFuture, pin_mut, stream::FuturesUnordered, FutureExt, StreamExt}; use futures::{
future::{BoxFuture, OptionFuture},
join, pin_mut,
stream::FuturesUnordered,
FutureExt, StreamExt,
};
use ruma::{ use ruma::{
api::{ api::{
appservice::event::push_events::v1::Edu as RumaEdu, appservice::event::push_events::v1::Edu as RumaEdu,
@ -261,33 +266,45 @@ impl Service {
#[tracing::instrument(skip_all, level = "debug")] #[tracing::instrument(skip_all, level = "debug")]
async fn select_edus(&self, server_name: &ServerName) -> Result<(Vec<Vec<u8>>, u64)> { async fn select_edus(&self, server_name: &ServerName) -> Result<(Vec<Vec<u8>>, u64)> {
// u64: count of last edu // selection window
let since = self.db.get_latest_educount(server_name).await; let since = self.db.get_latest_educount(server_name).await;
let mut max_edu_count = since; let since_upper = self.services.globals.current_count()?;
let mut events = Vec::new(); let batch = (since, since_upper);
debug_assert!(batch.0 <= batch.1, "since range must not be negative");
self.select_edus_device_changes(server_name, since, &mut max_edu_count, &mut events) let events_len = AtomicUsize::default();
.await; let max_edu_count = AtomicU64::new(since);
if self.server.config.allow_outgoing_read_receipts { let device_changes = self.select_edus_device_changes(server_name, batch, &max_edu_count, &events_len);
self.select_edus_receipts(server_name, since, &mut max_edu_count, &mut events)
.await;
}
if self.server.config.allow_outgoing_presence { let receipts: OptionFuture<_> = self
self.select_edus_presence(server_name, since, &mut max_edu_count, &mut events) .server
.await; .config
} .allow_outgoing_read_receipts
.then(|| self.select_edus_receipts(server_name, batch, &max_edu_count))
.into();
Ok((events, max_edu_count)) let presence: OptionFuture<_> = self
.server
.config
.allow_outgoing_presence
.then(|| self.select_edus_presence(server_name, batch, &max_edu_count))
.into();
let (device_changes, receipts, presence) = join!(device_changes, receipts, presence);
let mut events = device_changes;
events.extend(presence.into_iter().flatten());
events.extend(receipts.into_iter().flatten());
Ok((events, max_edu_count.load(Ordering::Acquire)))
} }
/// Look for presence /// Look for presence
async fn select_edus_device_changes( async fn select_edus_device_changes(
&self, server_name: &ServerName, since: u64, max_edu_count: &mut u64, events: &mut Vec<Vec<u8>>, &self, server_name: &ServerName, since: (u64, u64), max_edu_count: &AtomicU64, events_len: &AtomicUsize,
) { ) -> Vec<Vec<u8>> {
debug_assert!(events.len() < SELECT_EDU_LIMIT, "called when edu limit reached"); let mut events = Vec::new();
let server_rooms = self.services.state_cache.server_rooms(server_name); let server_rooms = self.services.state_cache.server_rooms(server_name);
pin_mut!(server_rooms); pin_mut!(server_rooms);
@ -296,12 +313,16 @@ impl Service {
let keys_changed = self let keys_changed = self
.services .services
.users .users
.room_keys_changed(room_id, since, None) .room_keys_changed(room_id, since.0, None)
.ready_filter(|(user_id, _)| self.services.globals.user_is_local(user_id)); .ready_filter(|(user_id, _)| self.services.globals.user_is_local(user_id));
pin_mut!(keys_changed); pin_mut!(keys_changed);
while let Some((user_id, count)) = keys_changed.next().await { while let Some((user_id, count)) = keys_changed.next().await {
*max_edu_count = cmp::max(count, *max_edu_count); if count > since.1 {
break;
}
max_edu_count.fetch_max(count, Ordering::Relaxed);
if !device_list_changes.insert(user_id.into()) { if !device_list_changes.insert(user_id.into()) {
continue; continue;
} }
@ -321,19 +342,19 @@ impl Service {
let edu = serde_json::to_vec(&edu).expect("failed to serialize device list update to JSON"); let edu = serde_json::to_vec(&edu).expect("failed to serialize device list update to JSON");
events.push(edu); events.push(edu);
if events.len() >= SELECT_EDU_LIMIT { if events_len.fetch_add(1, Ordering::Relaxed) >= SELECT_EDU_LIMIT - 1 {
return; return events;
} }
} }
} }
events
} }
/// Look for read receipts in this room /// Look for read receipts in this room
async fn select_edus_receipts( async fn select_edus_receipts(
&self, server_name: &ServerName, since: u64, max_edu_count: &mut u64, events: &mut Vec<Vec<u8>>, &self, server_name: &ServerName, since: (u64, u64), max_edu_count: &AtomicU64,
) { ) -> Option<Vec<u8>> {
debug_assert!(events.len() < EDU_LIMIT, "called when edu limit reached");
let server_rooms = self.services.state_cache.server_rooms(server_name); let server_rooms = self.services.state_cache.server_rooms(server_name);
pin_mut!(server_rooms); pin_mut!(server_rooms);
@ -350,7 +371,7 @@ impl Service {
} }
if receipts.is_empty() { if receipts.is_empty() {
return; return None;
} }
let receipt_content = Edu::Receipt(ReceiptContent { let receipt_content = Edu::Receipt(ReceiptContent {
@ -360,22 +381,26 @@ impl Service {
let receipt_content = let receipt_content =
serde_json::to_vec(&receipt_content).expect("Failed to serialize Receipt EDU to JSON vec"); serde_json::to_vec(&receipt_content).expect("Failed to serialize Receipt EDU to JSON vec");
events.push(receipt_content); Some(receipt_content)
} }
/// Look for read receipts in this room /// Look for read receipts in this room
async fn select_edus_receipts_room( async fn select_edus_receipts_room(
&self, room_id: &RoomId, since: u64, max_edu_count: &mut u64, num: &mut usize, &self, room_id: &RoomId, since: (u64, u64), max_edu_count: &AtomicU64, num: &mut usize,
) -> ReceiptMap { ) -> ReceiptMap {
let receipts = self let receipts = self
.services .services
.read_receipt .read_receipt
.readreceipts_since(room_id, since); .readreceipts_since(room_id, since.0);
pin_mut!(receipts); pin_mut!(receipts);
let mut read = BTreeMap::<OwnedUserId, ReceiptData>::new(); let mut read = BTreeMap::<OwnedUserId, ReceiptData>::new();
while let Some((user_id, count, read_receipt)) = receipts.next().await { while let Some((user_id, count, read_receipt)) = receipts.next().await {
*max_edu_count = cmp::max(count, *max_edu_count); if count > since.1 {
break;
}
max_edu_count.fetch_max(count, Ordering::Relaxed);
if !self.services.globals.user_is_local(user_id) { if !self.services.globals.user_is_local(user_id) {
continue; continue;
} }
@ -423,16 +448,18 @@ impl Service {
/// Look for presence /// Look for presence
async fn select_edus_presence( async fn select_edus_presence(
&self, server_name: &ServerName, since: u64, max_edu_count: &mut u64, events: &mut Vec<Vec<u8>>, &self, server_name: &ServerName, since: (u64, u64), max_edu_count: &AtomicU64,
) { ) -> Option<Vec<u8>> {
debug_assert!(events.len() < EDU_LIMIT, "called when edu limit reached"); let presence_since = self.services.presence.presence_since(since.0);
let presence_since = self.services.presence.presence_since(since);
pin_mut!(presence_since); pin_mut!(presence_since);
let mut presence_updates = HashMap::<OwnedUserId, PresenceUpdate>::new(); let mut presence_updates = HashMap::<OwnedUserId, PresenceUpdate>::new();
while let Some((user_id, count, presence_bytes)) = presence_since.next().await { while let Some((user_id, count, presence_bytes)) = presence_since.next().await {
*max_edu_count = cmp::max(count, *max_edu_count); if count > since.1 {
break;
}
max_edu_count.fetch_max(count, Ordering::Relaxed);
if !self.services.globals.user_is_local(user_id) { if !self.services.globals.user_is_local(user_id) {
continue; continue;
} }
@ -474,7 +501,7 @@ impl Service {
} }
if presence_updates.is_empty() { if presence_updates.is_empty() {
return; return None;
} }
let presence_content = Edu::Presence(PresenceContent { let presence_content = Edu::Presence(PresenceContent {
@ -483,7 +510,7 @@ impl Service {
let presence_content = serde_json::to_vec(&presence_content).expect("failed to serialize Presence EDU to JSON"); let presence_content = serde_json::to_vec(&presence_content).expect("failed to serialize Presence EDU to JSON");
events.push(presence_content); Some(presence_content)
} }
async fn send_events(&self, dest: Destination, events: Vec<SendingEvent>) -> SendingResult { async fn send_events(&self, dest: Destination, events: Vec<SendingEvent>) -> SendingResult {