Skip to content

Commit

Permalink
New data APIs 2: cached latest-at queries (#5581)
Browse files Browse the repository at this point in the history
Static-aware, key-less, component-based, cached latest-at APIs.

The overall structure of this new cache is very similar to what we had
before. Effectively it is just an extremely simplified version of
`re_query_cache`.

This introduces a new temporary `re_query_cache2` crate, which won't
ever be published.
It will replace the existing `re_query_cache` crate once all the
necessary features have been backported.

- Fixes #3232
- Fixes #4733
- Fixes #4734
- Part of #3379
- Part of #1893  

Example:
```rust
let caches = re_query_cache2::Caches::new(&store);

// First, get the results for this query.
//
// They might or might not already be cached. We won't know for sure until we try to access
// each individual component's data below.
let results: CachedLatestAtResults = caches.latest_at(
    &store,
    &query,
    &entity_path.into(),
    MyPoints::all_components().iter().cloned(), // no generics!
);

// Then, grab the results for each individual components.
// * `get_required` returns an error if the component batch is missing
// * `get_optional` returns an empty set of results if the component if missing
// * `get` returns an option
//
// At this point we still don't know whether they are cached or not. That's the next step.
let points: &CachedLatestAtComponentResults = results.get_required::<MyPoint>()?;
let colors: &CachedLatestAtComponentResults = results.get_optional::<MyColor>();
let labels: &CachedLatestAtComponentResults = results.get_optional::<MyLabel>();

// Then comes the time to resolve/convert and deserialize the data.
// These steps have to be done together for efficiency reasons.
//
// Both the resolution and deserialization steps might fail, which is why this returns a `Result<Result<T>>`.
// Use `PromiseResult::flatten` to simplify it down to a single result.
//
// A choice now has to be made regarding the nullability of the _component batch's instances_.
// Our IDL doesn't support nullable instances at the moment -- so for the foreseeable future you probably
// shouldn't be using anything but `iter_dense`.
//
// This is the step at which caching comes into play.
//
// If the data has already been accessed with the same nullability characteristics in the
// past, then this will just grab the pre-deserialized, pre-resolved/pre-converted result from
// the cache.
//
// Otherwise, this will trigger a deserialization and cache the result for next time.

let points = match points.iter_dense::<MyPoint>(&mut resolver).flatten() {
    PromiseResult::Pending => {
        // Handle the fact that the data isn't ready appropriately.
        return Ok(());
    }
    PromiseResult::Ready(data) => data,
    PromiseResult::Error(err) => return Err(err.into()),
};

let colors = match colors.iter_dense::<MyColor>(&mut resolver).flatten() {
    PromiseResult::Pending => {
        // Handle the fact that the data isn't ready appropriately.
        return Ok(());
    }
    PromiseResult::Ready(data) => data,
    PromiseResult::Error(err) => return Err(err.into()),
};

let labels = match labels.iter_sparse::<MyLabel>(&mut resolver).flatten() {
    PromiseResult::Pending => {
        // Handle the fact that the data isn't ready appropriately.
        return Ok(());
    }
    PromiseResult::Ready(data) => data,
    PromiseResult::Error(err) => return Err(err.into()),
};

// With the data now fully resolved/converted and deserialized, the joining logic can be
// applied.
//
// In most cases this will be either a clamped zip, or no joining at all.

let color_default_fn = || {
    static DEFAULT: MyColor = MyColor(0xFF00FFFF);
    &DEFAULT
};
let label_default_fn = || None;

let results =
    clamped_zip_1x2(points, colors, color_default_fn, labels, label_default_fn).collect_vec();
```


---

Part of a PR series to completely revamp the data APIs in preparation
for the removal of instance keys and the introduction of promises:
- #5573
- #5574
- #5581
- #5605
- #5606
- #5633
- #5673
- #5679
- #5687
- #5755
- TODO
- TODO

Builds on top of the static data PR series:
- #5534
  • Loading branch information
teh-cmc authored Apr 8, 2024
1 parent f0bbc15 commit 20dc298
Show file tree
Hide file tree
Showing 15 changed files with 3,242 additions and 1 deletion.
28 changes: 28 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ re_memory = { path = "crates/re_memory", version = "=0.15.0-alpha.5", default-fe
re_query = { path = "crates/re_query", version = "=0.15.0-alpha.5", default-features = false }
re_query2 = { path = "crates/re_query2", version = "=0.15.0-alpha.5", default-features = false }
re_query_cache = { path = "crates/re_query_cache", version = "=0.15.0-alpha.5", default-features = false }
re_query_cache2 = { path = "crates/re_query_cache2", version = "=0.15.0-alpha.5", default-features = false }
re_renderer = { path = "crates/re_renderer", version = "=0.15.0-alpha.5", default-features = false }
re_sdk = { path = "crates/re_sdk", version = "=0.15.0-alpha.5", default-features = false }
re_sdk_comms = { path = "crates/re_sdk_comms", version = "=0.15.0-alpha.5", default-features = false }
Expand Down
65 changes: 65 additions & 0 deletions crates/re_query_cache2/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
[package]
name = "re_query_cache2"
authors.workspace = true
description = "Temporary crate meant to replace re_query_cache"
edition.workspace = true
homepage.workspace = true
include.workspace = true
license.workspace = true
# TODO(cmc): Replace re_query with this crate. Never publish this one.
publish = false
readme = "README.md"
repository.workspace = true
rust-version.workspace = true
version.workspace = true

[package.metadata.docs.rs]
all-features = true


[features]
default = []

[dependencies]
# Rerun dependencies:
re_data_store.workspace = true
re_format.workspace = true
re_log.workspace = true
re_log_types.workspace = true
re_query2.workspace = true
re_tracing.workspace = true
re_types_core.workspace = true

# External dependencies:
ahash.workspace = true
anyhow.workspace = true
backtrace.workspace = true
indent.workspace = true
itertools.workspace = true
nohash-hasher.workspace = true
parking_lot.workspace = true
paste.workspace = true
seq-macro.workspace = true
web-time.workspace = true


[dev-dependencies]
re_types = { workspace = true, features = ["datagen"] }

criterion.workspace = true
mimalloc.workspace = true
rand = { workspace = true, features = ["std", "std_rng"] }
similar-asserts.workspace = true


[lib]
bench = false


[[bench]]
name = "flat_vec_deque"
harness = false

[[bench]]
name = "latest_at"
harness = false
5 changes: 5 additions & 0 deletions crates/re_query_cache2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# re_query_cache2

Temporary crate for implementing the new cached data APIs. Not published.

Will replace `re_query_cache2` when ready.
Loading

0 comments on commit 20dc298

Please sign in to comment.