Class ThreadSafeEntityCache
Defined in File thread_safe_entity_cache.hpp
Class Documentation
-
class ThreadSafeEntityCache
Thread-safe, index-optimized cache for SOVD entities.
Design principles:
Primary storage in vectors (cache-friendly, predictable memory)
Hash indexes for O(1) lookup by ID
Relationship indexes for O(1) aggregation queries
Reader-writer lock for concurrent access
Batch updates to minimize lock contention
Thread Safety:
Multiple readers can access concurrently (shared lock)
Writers get exclusive access (unique lock)
Readers never block each other
Writers block all readers and other writers
Usage:
Discovery thread calls update_*() methods (writer)
HTTP handlers call get_*() methods (reader)
Public Functions
-
ThreadSafeEntityCache() = default
-
void update_all(std::vector<Area> areas, std::vector<Component> components, std::vector<App> apps, std::vector<Function> functions, std::unordered_map<std::string, std::string> node_to_app = {})
Atomic batch update of all entities.
This is the preferred update method as it:
Minimizes lock hold time
Ensures readers never see partial state
Rebuilds all indexes in one pass
- Parameters:
areas – All discovered areas
components – All discovered components
apps – All discovered apps
functions – All discovered functions
node_to_app – Node FQN to app entity ID mapping from linking result (optional)
-
void update_areas(std::vector<Area> areas)
Incremental update for single entity type.
Use sparingly - prefer update_all() for full refresh. Each call acquires exclusive lock and rebuilds relevant indexes.
-
void update_topic_types(std::unordered_map<std::string, std::string> topic_types)
Update cached topic type mapping.
Called during cache refresh to cache topic name -> message type mapping. This avoids expensive ROS graph queries on every /data request.
- Parameters:
topic_types – Map of topic name to message type
-
bool has_area(const std::string &id) const
-
bool has_component(const std::string &id) const
-
bool has_app(const std::string &id) const
-
bool has_function(const std::string &id) const
-
std::string get_topic_type(const std::string &topic_name) const
Get cached message type for a topic.
- Parameters:
topic_name – Full topic path (e.g., “/sensor/temperature”)
- Returns:
Message type string, or empty if not cached
-
std::unordered_map<std::string, std::string> get_node_to_app() const
Get the node FQN to app entity ID mapping.
Used by trigger subscribers to resolve ROS 2 node FQNs to manifest entity IDs. The mapping is populated from the linking result during cache refresh.
- Returns:
Map of node FQN -> app entity ID (empty if no linking available)
-
std::string resolve_node_to_app(const std::string &node_fqn) const
Look up a single node FQN to app entity ID mapping (shared lock, no map copy)
-
SovdEntityType get_entity_type(const std::string &id) const
-
std::vector<std::string> get_apps_for_component(const std::string &component_id) const
Get Apps hosted on a Component.
- Returns:
Vector of App IDs (empty if component not found)
-
std::vector<std::string> get_components_for_area(const std::string &area_id) const
Get Components in an Area.
- Returns:
Vector of Component IDs (empty if area not found)
-
std::vector<std::string> get_apps_for_function(const std::string &function_id) const
Get Apps implementing a Function.
- Returns:
Vector of App IDs (empty if function not found)
-
std::vector<std::string> get_subareas(const std::string &area_id) const
Get subareas of an Area.
- Returns:
Vector of Area IDs (empty if area not found or no subareas)
-
AggregatedOperations get_app_operations(const std::string &app_id) const
Aggregate operations for an App (no aggregation, returns own ops)
-
AggregatedOperations get_component_operations(const std::string &component_id) const
Aggregate operations for a Component.
Returns: Component’s own operations + all operations from hosted Apps. Deduplicates by operation full_path.
-
AggregatedOperations get_area_operations(const std::string &area_id) const
Aggregate operations for an Area (x-medkit extension)
Returns: All operations from all Components in the Area. Recursive through Component→App hierarchy.
Note: This is a ros2_medkit extension. SOVD spec doesn’t allow Area to have resource collections.
-
AggregatedOperations get_function_operations(const std::string &function_id) const
Aggregate operations for a Function.
Returns: All operations from all Apps implementing this Function.
-
AggregatedData get_entity_data(const std::string &entity_id) const
Aggregate data (topics) for any entity by ID.
Unified method that works for all entity types. Aggregates topics from the entity and its children.
- Parameters:
entity_id – Entity ID to get data for
- Returns:
AggregatedData with topics, or empty if entity not found
-
AggregatedData get_app_data(const std::string &app_id) const
Aggregate data (topics) for an App.
-
AggregatedData get_component_data(const std::string &component_id) const
Aggregate data (topics) for a Component.
Returns: Component’s own topics + all topics from hosted Apps.
-
AggregatedData get_area_data(const std::string &area_id) const
Aggregate data (topics) for an Area.
Returns: All topics from all Components in the Area.
-
AggregatedData get_function_data(const std::string &function_id) const
Aggregate data (topics) for a Function.
Returns: All topics from all Apps implementing this Function.
-
AggregatedConfigurations get_entity_configurations(const std::string &entity_id) const
Aggregate configurations (node FQNs) for any entity by ID.
Unified method that works for all entity types. For Apps, returns the single bound node. For Components/Areas/Functions, aggregates all child app nodes.
- Parameters:
entity_id – Entity ID to get configurations for
- Returns:
AggregatedConfigurations with node FQNs, or empty if entity not found
-
AggregatedConfigurations get_app_configurations(const std::string &app_id) const
Get configurations for an App (returns its single bound node)
-
AggregatedConfigurations get_component_configurations(const std::string &component_id) const
Aggregate configurations for a Component.
Returns: All node FQNs from hosted Apps.
-
AggregatedConfigurations get_area_configurations(const std::string &area_id) const
Aggregate configurations for an Area.
Returns: All node FQNs from all Components in the Area.
-
AggregatedConfigurations get_function_configurations(const std::string &function_id) const
Aggregate configurations for a Function.
Returns: All node FQNs from all Apps implementing this Function.
-
std::optional<EntityRef> find_operation_owner(const std::string &operation_path) const
Find which entity owns an operation by full path.
- Parameters:
operation_path – e.g., “/nav2/navigate_to_pose”
- Returns:
EntityRef if found
-
EntityCacheStats get_stats() const
Get cache statistics.
-
std::string validate() const
Validate internal consistency.
Checks:
All indexes point to valid vector entries
Relationship indexes are consistent
No duplicate IDs within entity type
- Returns:
Empty string if valid, error message otherwise
-
std::chrono::system_clock::time_point get_last_update() const
Get last update timestamp.
-
uint64_t generation() const
Get the current generation counter.
The generation counter is incremented on every cache mutation (update_all, update_areas, update_components, update_apps, update_functions). Consumers can use this to detect when cached derived data (e.g., OpenAPI specs) is stale and needs regeneration.