Skip to content

Commit 00fe624

Browse files
Add caching for rosparam get requests (#193)
1 parent 7b178b1 commit 00fe624

File tree

7 files changed

+123
-8
lines changed

7 files changed

+123
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## Rosrust Unreleased
4+
### Added
5+
- Automatic caching of parameters
6+
37
## Rosrust Msg 0.1.7 (2023-04-01)
48
### Added
59
- Find messages in `ROS_PACKAGE_PATH`
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use std::time::Instant;
2+
3+
mod msg {
4+
rosrust::rosmsg_include!(std_msgs / String);
5+
}
6+
7+
fn main() {
8+
env_logger::init();
9+
10+
// Initialize node
11+
rosrust::init("talker");
12+
13+
// Create publisher
14+
let chatter_pub = rosrust::publish("chatter", 2).unwrap();
15+
chatter_pub.wait_for_subscribers(None).unwrap();
16+
17+
let message = rosrust::param("~message").unwrap();
18+
19+
let log_names = rosrust::param("~log_names").unwrap().get().unwrap_or(false);
20+
21+
// Create object that maintains 10Hz between sleep requests
22+
let rate = rosrust::rate(10.0);
23+
24+
// Breaks when a shutdown signal is sent
25+
while rosrust::is_ok() {
26+
let t = Instant::now();
27+
let message = message.get_raw().unwrap_or(xml_rpc::Value::Bool(false));
28+
let message_fetch_time = t.elapsed();
29+
// Create string message
30+
let msg = msg::std_msgs::String {
31+
data: format!("{:?} from rosrust in {:?}", message, message_fetch_time),
32+
};
33+
34+
// Log event
35+
rosrust::ros_info!("Publishing: {}", msg.data);
36+
37+
// Send string message to topic via publisher
38+
chatter_pub.send(msg).unwrap();
39+
40+
if log_names {
41+
rosrust::ros_info!("Subscriber names: {:?}", chatter_pub.subscriber_names());
42+
}
43+
44+
// Sleep to maintain 10Hz rate
45+
rate.sleep();
46+
}
47+
}

rosrust/src/api/ros.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ use super::resolve;
88
use super::slave::Slave;
99
use crate::api::clock::Delay;
1010
use crate::api::handlers::CallbackSubscriptionHandler;
11+
use crate::api::slave::ParamCache;
1112
use crate::api::ShutdownManager;
1213
use crate::msg::rosgraph_msgs::{Clock as ClockMsg, Log};
1314
use crate::msg::std_msgs::Header;
15+
use crate::rosxmlrpc::client::bad_response_structure;
1416
use crate::tcpros::{Client, Message, ServicePair, ServiceResult};
1517
use crate::util::FAILED_TO_LOCK;
1618
use crate::{RawMessage, RawMessageDescription, SubscriptionHandler};
@@ -31,6 +33,7 @@ use yaml_rust::{Yaml, YamlLoader};
3133
pub struct Ros {
3234
master: Arc<Master>,
3335
slave: Arc<Slave>,
36+
param_cache: ParamCache,
3437
hostname: String,
3538
bind_address: String,
3639
resolver: Resolver,
@@ -111,19 +114,22 @@ impl Ros {
111114
move || drop(logger.lock().unwrap().take())
112115
}));
113116

117+
let param_cache = Arc::new(Mutex::new(Default::default()));
114118
let slave = Slave::new(
115119
master_uri,
116120
hostname,
117121
bind_host,
118122
0,
119123
&name,
124+
Arc::clone(&param_cache),
120125
Arc::clone(&shutdown_manager),
121126
)?;
122127
let master = Master::new(master_uri, &name, slave.uri())?;
123128

124129
Ok(Ros {
125130
master: Arc::new(master),
126131
slave: Arc::new(slave),
132+
param_cache,
127133
hostname: String::from(hostname),
128134
bind_address: String::from(bind_host),
129135
resolver,
@@ -195,6 +201,7 @@ impl Ros {
195201

196202
pub fn param(&self, name: &str) -> Option<Parameter> {
197203
self.resolver.translate(name).ok().map(|v| Parameter {
204+
param_cache: Arc::clone(&self.param_cache),
198205
master: Arc::clone(&self.master),
199206
name: v,
200207
})
@@ -484,6 +491,7 @@ impl Ros {
484491
}
485492

486493
pub struct Parameter {
494+
param_cache: ParamCache,
487495
master: Arc<Master>,
488496
name: String,
489497
}
@@ -494,11 +502,30 @@ impl Parameter {
494502
}
495503

496504
pub fn get<'b, T: Deserialize<'b>>(&self) -> Response<T> {
497-
self.master.get_param::<T>(&self.name)
505+
let data = self.get_raw()?;
506+
Deserialize::deserialize(data).map_err(bad_response_structure)
498507
}
499508

500509
pub fn get_raw(&self) -> Response<xml_rpc::Value> {
501-
self.master.get_param_any(&self.name)
510+
let subscribed;
511+
{
512+
let cache = self.param_cache.lock().expect(FAILED_TO_LOCK);
513+
if let Some(data) = cache.data.get(&self.name) {
514+
return data.clone();
515+
}
516+
subscribed = cache.subscribed;
517+
}
518+
if !subscribed {
519+
self.master.subscribe_param_any("/")?;
520+
self.param_cache.lock().expect(FAILED_TO_LOCK).subscribed = true;
521+
}
522+
let data = self.master.get_param_any(&self.name);
523+
self.param_cache
524+
.lock()
525+
.expect(FAILED_TO_LOCK)
526+
.data
527+
.insert(self.name.clone(), data.clone());
528+
data
502529
}
503530

504531
pub fn set<T: Serialize>(&self, value: &T) -> Response<()> {

rosrust/src/api/slave/handler.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::publications::PublicationsTracker;
22
use super::subscriptions::SubscriptionsTracker;
33
use crate::rosxmlrpc::{self, Response, ResponseError, Server};
44
use crate::tcpros::Service;
5-
use crate::util::kill;
5+
use crate::util::{kill, FAILED_TO_LOCK};
66
use log::{error, info};
77
use std::collections::HashMap;
88
use std::net::SocketAddr;
@@ -23,11 +23,20 @@ fn unwrap_array_case(params: Params) -> Params {
2323
params
2424
}
2525

26+
#[derive(Default)]
27+
pub struct ParamCacheState {
28+
pub data: HashMap<String, Response<Value>>,
29+
pub subscribed: bool,
30+
}
31+
32+
pub type ParamCache = Arc<Mutex<ParamCacheState>>;
33+
2634
impl SlaveHandler {
2735
pub fn new(
2836
master_uri: &str,
2937
hostname: &str,
3038
name: &str,
39+
param_cache: ParamCache,
3140
shutdown_signal: kill::Sender,
3241
) -> SlaveHandler {
3342
let mut server = Server::default();
@@ -105,8 +114,33 @@ impl SlaveHandler {
105114
))
106115
});
107116

108-
server.register_value("paramUpdate", "Parameter updated", |_args| {
109-
// We don't do anything with parameter updates
117+
server.register_value("paramUpdate", "Parameter updated", move |args| {
118+
let mut args = unwrap_array_case(args).into_iter();
119+
let _caller_id = args
120+
.next()
121+
.ok_or_else(|| ResponseError::Client("Missing argument 'caller_id'".into()))?;
122+
let parameter_key = match args.next() {
123+
Some(Value::String(parameter_key)) => parameter_key,
124+
_ => {
125+
return Err(ResponseError::Client(
126+
"Missing argument 'parameter_key'".into(),
127+
))
128+
}
129+
};
130+
let _parameter_value = match args.next() {
131+
Some(parameter_value) => parameter_value,
132+
_ => {
133+
return Err(ResponseError::Client(
134+
"Missing argument 'parameter_key'".into(),
135+
))
136+
}
137+
};
138+
let key = parameter_key.trim_end_matches('/');
139+
param_cache
140+
.lock()
141+
.expect(FAILED_TO_LOCK)
142+
.data
143+
.retain(|k, _| !k.starts_with(key) && !key.starts_with(k));
110144
Ok(Value::Int(0))
111145
});
112146

rosrust/src/api/slave/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod handler;
22
mod publications;
33
mod subscriptions;
44

5+
pub use self::handler::ParamCache;
56
use self::handler::SlaveHandler;
67
use super::error::{self, ErrorKind, Result};
78
use crate::api::ShutdownManager;
@@ -33,12 +34,14 @@ impl Slave {
3334
bind_address: &str,
3435
port: u16,
3536
name: &str,
37+
param_cache: ParamCache,
3638
shutdown_manager: Arc<ShutdownManager>,
3739
) -> Result<Slave> {
3840
use std::net::ToSocketAddrs;
3941

4042
let (shutdown_tx, shutdown_rx) = kill::channel(kill::KillMode::Sync);
41-
let handler = SlaveHandler::new(master_uri, hostname, name, shutdown_tx.clone());
43+
let handler =
44+
SlaveHandler::new(master_uri, hostname, name, param_cache, shutdown_tx.clone());
4245
let publications = handler.publications.clone();
4346
let subscriptions = handler.subscriptions.clone();
4447
let services = Arc::clone(&handler.services);

rosrust/src/rosxmlrpc/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,6 @@ fn bad_request_structure<T: ::std::fmt::Display>(err: T) -> ResponseError {
6363
ResponseError::Client(format!("Failed to serialize parameters: {}", err))
6464
}
6565

66-
fn bad_response_structure<T: ::std::fmt::Display>(err: T) -> ResponseError {
66+
pub(crate) fn bad_response_structure<T: ::std::fmt::Display>(err: T) -> ResponseError {
6767
ResponseError::Server(format!("Response data has unexpected structure: {}", err))
6868
}

rosrust/src/rosxmlrpc/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub mod server;
99

1010
pub type Response<T> = Result<T, ResponseError>;
1111

12-
#[derive(Debug)]
12+
#[derive(Clone, Debug)]
1313
pub enum ResponseError {
1414
Client(String),
1515
Server(String),

0 commit comments

Comments
 (0)