···218218}
219219/// Collection stats
220220///
221221-/// Get record statistics for collections during a specific time period
221221+/// Get record statistics for collections during a specific time period.
222222+///
223223+/// Note: the statistics are "rolled up" into hourly buckets in the background,
224224+/// so the data here can be as stale as that background task is behind. See the
225225+/// meta info endpoint to find out how up-to-date the rollup currently is. (In
226226+/// general it sholud be pretty close to live)
222227#[endpoint {
223228 method = GET,
224229 path = "/collections/stats"
+28-32
ufos/src/storage_fjall.rs
···718718 fn get_counts_by_collection(
719719 &self,
720720 collection: &Nsid,
721721- _since: HourTruncatedCursor,
722722- _until: Option<HourTruncatedCursor>,
721721+ since: HourTruncatedCursor,
722722+ until: Option<HourTruncatedCursor>,
723723 ) -> StorageResult<(u64, u64)> {
724724- // 0. grab a snapshot in case rollups happen while we're working
725725- let instant = self.keyspace.instant();
726726- let global = self.global.snapshot_at(instant);
727727- let rollups = self.rollups.snapshot_at(instant);
724724+ // grab snapshots in case rollups happen while we're working
725725+ let rollups = self.rollups.snapshot();
728726729729- // 1. all-time counts
730730- let all_time_key = AllTimeRollupKey::new(collection).to_db_bytes()?;
731731- let mut total_counts = rollups
732732- .get(&all_time_key)?
733733- .as_deref()
734734- .map(db_complete::<CountsValue>)
735735- .transpose()?
736736- .unwrap_or_default();
727727+ let until = until.unwrap_or_else(|| Cursor::at(SystemTime::now()).into());
728728+ let buckets = CursorBucket::buckets_spanning(since, until);
729729+ let mut total_counts = CountsValue::default();
737730738738- // 2. live counts that haven't been rolled into all-time yet.
739739- let rollup_cursor =
740740- get_snapshot_static_neu::<NewRollupCursorKey, NewRollupCursorValue>(&global)?.ok_or(
741741- StorageError::BadStateError("Could not find current rollup cursor".to_string()),
742742- )?;
743743-744744- let full_range = LiveCountsKey::range_from_cursor(rollup_cursor)?;
745745- for kv in rollups.range(full_range) {
746746- let (key_bytes, val_bytes) = kv?;
747747- let key = db_complete::<LiveCountsKey>(&key_bytes)?;
748748- if key.collection() == collection {
749749- let counts = db_complete::<CountsValue>(&val_bytes)?;
750750- total_counts.merge(&counts);
751751- }
731731+ for bucket in buckets {
732732+ let key = match bucket {
733733+ CursorBucket::Hour(t) => HourlyRollupKey::new(t, collection).to_db_bytes()?,
734734+ CursorBucket::Week(t) => WeeklyRollupKey::new(t, collection).to_db_bytes()?,
735735+ CursorBucket::AllTime => unreachable!(), // TODO: fall back on this if the time span spans the whole dataset?
736736+ };
737737+ let count = rollups
738738+ .get(&key)?
739739+ .as_deref()
740740+ .map(db_complete::<CountsValue>)
741741+ .transpose()?
742742+ .unwrap_or_default();
743743+ total_counts.merge(&count);
752744 }
745745+753746 Ok((
754747 total_counts.counts().creates,
755748 total_counts.dids().estimate() as u64,
···16621655 100,
16631656 );
16641657 write.insert_batch(batch.batch)?;
16581658+ write.step_rollup()?;
1665165916661660 let (records, dids) = read.get_counts_by_collection(&collection, beginning(), None)?;
16671661 assert_eq!(records, 1);
···18361830 101,
18371831 );
18381832 write.insert_batch(batch.batch)?;
18331833+ write.step_rollup()?;
1839183418401835 let (records, dids) = read.get_counts_by_collection(&collection, beginning(), None)?;
18411836 assert_eq!(records, 1);
···18741869 101,
18751870 );
18761871 write.insert_batch(batch.batch)?;
18721872+ write.step_rollup()?;
1877187318781874 let (creates, dids) = read.get_counts_by_collection(&collection, beginning(), None)?;
18791875 assert_eq!(creates, 1);
···21962192 beginning(),
21972193 None,
21982194 )?;
21992199- assert_eq!(records, 3);
22002200- assert_eq!(dids, 2);
21952195+ assert_eq!(records, 0);
21962196+ assert_eq!(dids, 0);
2201219722022198 // first batch rolled up
22032199 let (n, _) = write.step_rollup()?;
···22082204 beginning(),
22092205 None,
22102206 )?;
22112211- assert_eq!(records, 3);
22072207+ assert_eq!(records, 2);
22122208 assert_eq!(dids, 2);
2213220922142210 // delete account rolled up
···22202216 beginning(),
22212217 None,
22222218 )?;
22232223- assert_eq!(records, 3);
22192219+ assert_eq!(records, 2);
22242220 assert_eq!(dids, 2);
2225222122262222 // second batch rolled up