Skip to content

Commit 85d8591

Browse files
authored
Merge pull request #163 from progval/list_targets
Fix LocalHistoryService::list_targets to take the latest timestamp of each target
2 parents df7bc30 + 1d75feb commit 85d8591

File tree

4 files changed

+61
-18
lines changed

4 files changed

+61
-18
lines changed

Cargo.lock

Lines changed: 13 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sable_network/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ tokio-rustls = "0.23"
3333
rustls = "0.20"
3434
rustls-pemfile = "0.2"
3535
bitflags = "1.3"
36-
itertools = "0.10"
36+
itertools = "0.14"
3737
futures = "0.3"
3838
x509-parser = "0.13"
3939
sha1 = "0.10"

sable_network/src/history/local_service.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use std::collections::HashMap;
1+
use std::collections::{HashMap, HashSet};
22
use std::num::NonZeroUsize;
33

4+
use itertools::Itertools;
45
use tracing::instrument;
56

67
use crate::network::state::HistoricMessageTargetId;
@@ -185,32 +186,47 @@ impl<NetworkPolicy: policy::PolicyService> HistoryService
185186
before_ts: Option<i64>,
186187
limit: Option<NonZeroUsize>,
187188
) -> HashMap<TargetId, i64> {
189+
// Targets that have an entry whose timestamp is after after_ts
190+
let mut excluded_targets = HashSet::new();
191+
188192
let mut found_targets = HashMap::new();
189193

190-
for entry in self.node.history().entries_for_user(user) {
191-
if matches!(before_ts, Some(ts) if entry.timestamp <= ts) {
192-
// Skip over until we hit the timestamp window we're interested in
194+
for entry in self.node.history().entries_for_user_reverse(user) {
195+
if matches!(after_ts, Some(ts) if entry.timestamp >= ts) {
196+
// Skip over until we hit the timestamp window we're interested in;
197+
// and exclude all targets we find in that window, because they have
198+
// an entry that is more recent than requested
199+
if let Some(target_id) = target_id_for_entry(user, entry) {
200+
excluded_targets.insert(target_id);
201+
}
193202
continue;
194203
}
195-
if matches!(after_ts, Some(ts) if entry.timestamp >= ts) {
196-
// We're iterating forwards through time; if we hit this then we've
204+
if matches!(before_ts, Some(ts) if entry.timestamp <= ts) {
205+
// We're iterating backwards through time; if we hit this then we've
197206
// passed the requested window and should stop
198207
break;
199208
}
200209

201210
if let Some(target_id) = target_id_for_entry(user, entry) {
202-
found_targets.insert(target_id, entry.timestamp);
203-
}
204-
205-
// If this pushes us past the requested limit, stop
206-
if matches!(limit, Some(limit) if usize::from(limit) <= found_targets.len()) {
207-
break;
211+
if !excluded_targets.contains(&target_id) {
212+
// if the target is already listed, keep the existing timestamp
213+
// (which is newer than the one of the current entry)
214+
found_targets.entry(target_id).or_insert(entry.timestamp);
215+
}
208216
}
209217
}
210218

211219
tracing::trace!("list_targets local response: {found_targets:?}");
212220

213-
found_targets
221+
if let Some(limit) = limit {
222+
// Sort by ascending timestamp, and keep the smallest ones (ie. oldest)
223+
found_targets
224+
.into_iter()
225+
.k_smallest_relaxed_by_key(usize::from(limit), |(_target_id, ts)| *ts)
226+
.collect()
227+
} else {
228+
found_targets
229+
}
214230
}
215231

216232
#[instrument(skip(self))]

sable_network/src/history/service.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,24 @@ pub trait HistoryService {
8888
/// Returns a list of list of history logs the given user has access to
8989
///
9090
/// And the timestamp of the last known message in that log.
91+
///
92+
/// `after_ts` and `before_ts` are matched against that timestamp,
93+
/// and they are ordered by that timestamp in ascending order before
94+
/// applying the `limit`.
95+
///
96+
/// In pseudo-SQL, this means:
97+
///
98+
/// ```text
99+
/// SELECT target_id, last_timestamp
100+
/// FROM (
101+
/// SELECT target_id, MAX(timestamp)
102+
/// FROM entries
103+
/// GROUP BY target_id
104+
/// )
105+
/// WHERE :before_ts < last_timestamp AND last_timestamp < :after_ts
106+
/// ORDER BY last_timestamp
107+
/// LIMIT :limit
108+
/// ```
91109
fn list_targets(
92110
&self,
93111
user: UserId,

0 commit comments

Comments
 (0)