-
Notifications
You must be signed in to change notification settings - Fork 71
Description
TLDR: Several request builders internally use ..Default::default()
in their new()
constructor to fill None
values. The problem is that this actually constructs not only the None
values, but also Client::default()
(due to how ..Default::default()
works).
Client::default()
takes quite a long time (roughly 60ms on my system) and also I am quite sure its not intended to be constructed every time.
Reproduction / examples
It is the most pronounced on get_presigned_object_url
, because that should be a very cheap call. On the current master
branch, the following code:
let start = std::time::Instant::now();
let req = client.get_presigned_object_url("foo", "bar", Method.GET);
println("took {:?}", start.elapsed());
takes at least 60ms on my system.
Changing the implementation of GetPresignedObjectUrl::new
like this: (replaces ..Default::default()
with explicit assignments of None
)
Self {
client,
bucket,
object,
method,
expiry_seconds: Some(DEFAULT_EXPIRY_SECONDS),
extra_query_params: None,
request_time: None,
version_id: None,
region: None,
}
changes the time it takes to 2.28µs
Fix
I am happy to submit a patch/PR for fix, but I would like to first discuss the approach.
In my opinion, the best course of action would be to eliminate the default()
on Client
, because I think its too easy to then use it somewhere by mistake and cause built-in latency on key logic.
That said, given that would be API breaking change, at minimum we need to eliminate Default
derive on structs like GetPresignedObjectUrl
, and make sure its not added again in the future. And replace ..Default::default()
with explicit None
assignments.
Finally I suggest we add tests, at least for the get_presigned_object_url
case, because that one is the most affected. In our case where we sign 50 URLs, the difference in how long this takes is from 4s to 4ms.