Bitemporal scan: resolve the ceiling for every cell coordinate at the given `system_as_of` and optional `valid_at_ms` point. Returns one `(hilbert_prefix, SparseTile)` pair per prefix that has at least one `Live` cell after ceiling resolution. Tombstoned and erased coords are omitted. Also returns `truncated_before_horizon`: `true` when the store contains at least one tile version but the `syste
(
&self,
system_as_of: i64,
valid_at_ms: Option<i64>,
)
| 253 | /// at least one tile version but the `system_as_of` cutoff is below every |
| 254 | /// version's `system_from_ms` (i.e., the cutoff predates all data). |
| 255 | pub fn scan_tiles_at( |
| 256 | &self, |
| 257 | system_as_of: i64, |
| 258 | valid_at_ms: Option<i64>, |
| 259 | ) -> Result<(Vec<(u64, SparseTile)>, bool), nodedb_array::ArrayError> { |
| 260 | let params = CeilingParams { |
| 261 | system_as_of, |
| 262 | valid_at_ms, |
| 263 | }; |
| 264 | |
| 265 | // Collect all distinct hilbert_prefix values present in any version. |
| 266 | let mut all_prefixes: HashSet<u64> = HashSet::new(); |
| 267 | for h in self.segments.values() { |
| 268 | let reader = h.reader(); |
| 269 | for entry in reader.tiles() { |
| 270 | all_prefixes.insert(entry.tile_id.hilbert_prefix); |
| 271 | } |
| 272 | } |
| 273 | for (tile_id, _) in self.memtable.iter() { |
| 274 | all_prefixes.insert(tile_id.hilbert_prefix); |
| 275 | } |
| 276 | |
| 277 | // Did any version exist at all in the store? |
| 278 | let any_versions = !all_prefixes.is_empty(); |
| 279 | |
| 280 | let mut out: Vec<(u64, SparseTile)> = Vec::new(); |
| 281 | let mut any_qualifying = false; |
| 282 | |
| 283 | for prefix in all_prefixes { |
| 284 | // Collect all distinct coords across every version for this prefix. |
| 285 | let mut coords: Vec<Vec<CoordValue>> = Vec::new(); |
| 286 | |
| 287 | // From memtable versions. |
| 288 | for (_, buf) in self.memtable.iter_tile_versions(prefix, i64::MAX) { |
| 289 | for coord_key in buf.all_coord_keys() { |
| 290 | let coord = Memtable::decode_coord_key(coord_key)?; |
| 291 | if !coords.contains(&coord) { |
| 292 | coords.push(coord); |
| 293 | } |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | // From segment versions (newest-first per segment, but we only need |
| 298 | // coords here so order within a segment doesn't matter). |
| 299 | for h in self.segments.values() { |
| 300 | let reader = h.reader(); |
| 301 | for item in reader.iter_tile_versions(prefix, i64::MAX)? { |
| 302 | let (_, tile_payload) = item?; |
| 303 | if let TilePayload::Sparse(sparse) = &tile_payload { |
| 304 | let n = sparse.nnz() as usize; |
| 305 | for row in 0..n { |
| 306 | let coord: Vec<CoordValue> = sparse |
| 307 | .dim_dicts |
| 308 | .iter() |
| 309 | .map(|d| d.values[d.indices[row] as usize].clone()) |
| 310 | .collect(); |
| 311 | if !coords.contains(&coord) { |
| 312 | coords.push(coord); |