mirror of
https://github.com/esphome/esphome.git
synced 2026-05-27 11:56:11 +08:00
[scheduler] Avoid std::string allocation in RetryArgs (#12311)
This commit is contained in:
@@ -138,10 +138,19 @@ void Component::set_retry(const std::string &name, uint32_t initial_wait_time, u
|
|||||||
App.scheduler.set_retry(this, name, initial_wait_time, max_attempts, std::move(f), backoff_increase_factor);
|
App.scheduler.set_retry(this, name, initial_wait_time, max_attempts, std::move(f), backoff_increase_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Component::set_retry(const char *name, uint32_t initial_wait_time, uint8_t max_attempts,
|
||||||
|
std::function<RetryResult(uint8_t)> &&f, float backoff_increase_factor) { // NOLINT
|
||||||
|
App.scheduler.set_retry(this, name, initial_wait_time, max_attempts, std::move(f), backoff_increase_factor);
|
||||||
|
}
|
||||||
|
|
||||||
bool Component::cancel_retry(const std::string &name) { // NOLINT
|
bool Component::cancel_retry(const std::string &name) { // NOLINT
|
||||||
return App.scheduler.cancel_retry(this, name);
|
return App.scheduler.cancel_retry(this, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Component::cancel_retry(const char *name) { // NOLINT
|
||||||
|
return App.scheduler.cancel_retry(this, name);
|
||||||
|
}
|
||||||
|
|
||||||
void Component::set_timeout(const std::string &name, uint32_t timeout, std::function<void()> &&f) { // NOLINT
|
void Component::set_timeout(const std::string &name, uint32_t timeout, std::function<void()> &&f) { // NOLINT
|
||||||
App.scheduler.set_timeout(this, name, timeout, std::move(f));
|
App.scheduler.set_timeout(this, name, timeout, std::move(f));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -367,6 +367,9 @@ class Component {
|
|||||||
void set_retry(const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts, // NOLINT
|
void set_retry(const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts, // NOLINT
|
||||||
std::function<RetryResult(uint8_t)> &&f, float backoff_increase_factor = 1.0f); // NOLINT
|
std::function<RetryResult(uint8_t)> &&f, float backoff_increase_factor = 1.0f); // NOLINT
|
||||||
|
|
||||||
|
void set_retry(const char *name, uint32_t initial_wait_time, uint8_t max_attempts, // NOLINT
|
||||||
|
std::function<RetryResult(uint8_t)> &&f, float backoff_increase_factor = 1.0f); // NOLINT
|
||||||
|
|
||||||
void set_retry(uint32_t initial_wait_time, uint8_t max_attempts, std::function<RetryResult(uint8_t)> &&f, // NOLINT
|
void set_retry(uint32_t initial_wait_time, uint8_t max_attempts, std::function<RetryResult(uint8_t)> &&f, // NOLINT
|
||||||
float backoff_increase_factor = 1.0f); // NOLINT
|
float backoff_increase_factor = 1.0f); // NOLINT
|
||||||
|
|
||||||
@@ -376,6 +379,7 @@ class Component {
|
|||||||
* @return Whether a retry function was deleted.
|
* @return Whether a retry function was deleted.
|
||||||
*/
|
*/
|
||||||
bool cancel_retry(const std::string &name); // NOLINT
|
bool cancel_retry(const std::string &name); // NOLINT
|
||||||
|
bool cancel_retry(const char *name); // NOLINT
|
||||||
|
|
||||||
/** Set a timeout function with a unique name.
|
/** Set a timeout function with a unique name.
|
||||||
*
|
*
|
||||||
|
|||||||
+39
-10
@@ -204,13 +204,21 @@ bool HOT Scheduler::cancel_interval(Component *component, const char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct RetryArgs {
|
struct RetryArgs {
|
||||||
|
// Ordered to minimize padding on 32-bit systems
|
||||||
std::function<RetryResult(uint8_t)> func;
|
std::function<RetryResult(uint8_t)> func;
|
||||||
uint8_t retry_countdown;
|
|
||||||
uint32_t current_interval;
|
|
||||||
Component *component;
|
Component *component;
|
||||||
std::string name; // Keep as std::string since retry uses it dynamically
|
|
||||||
float backoff_increase_factor;
|
|
||||||
Scheduler *scheduler;
|
Scheduler *scheduler;
|
||||||
|
const char *name; // Points to static string or owned copy
|
||||||
|
uint32_t current_interval;
|
||||||
|
float backoff_increase_factor;
|
||||||
|
uint8_t retry_countdown;
|
||||||
|
bool name_is_dynamic; // True if name needs delete[]
|
||||||
|
|
||||||
|
~RetryArgs() {
|
||||||
|
if (this->name_is_dynamic && this->name) {
|
||||||
|
delete[] this->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void retry_handler(const std::shared_ptr<RetryArgs> &args) {
|
void retry_handler(const std::shared_ptr<RetryArgs> &args) {
|
||||||
@@ -218,8 +226,10 @@ void retry_handler(const std::shared_ptr<RetryArgs> &args) {
|
|||||||
if (retry_result == RetryResult::DONE || args->retry_countdown <= 0)
|
if (retry_result == RetryResult::DONE || args->retry_countdown <= 0)
|
||||||
return;
|
return;
|
||||||
// second execution of `func` happens after `initial_wait_time`
|
// second execution of `func` happens after `initial_wait_time`
|
||||||
|
// Pass is_static_string=true because args->name is owned by the shared_ptr<RetryArgs>
|
||||||
|
// which is captured in the lambda and outlives the SchedulerItem
|
||||||
args->scheduler->set_timer_common_(
|
args->scheduler->set_timer_common_(
|
||||||
args->component, Scheduler::SchedulerItem::TIMEOUT, false, &args->name, args->current_interval,
|
args->component, Scheduler::SchedulerItem::TIMEOUT, true, args->name, args->current_interval,
|
||||||
[args]() { retry_handler(args); }, /* is_retry= */ true);
|
[args]() { retry_handler(args); }, /* is_retry= */ true);
|
||||||
// backoff_increase_factor applied to third & later executions
|
// backoff_increase_factor applied to third & later executions
|
||||||
args->current_interval *= args->backoff_increase_factor;
|
args->current_interval *= args->backoff_increase_factor;
|
||||||
@@ -246,16 +256,35 @@ void HOT Scheduler::set_retry_common_(Component *component, bool is_static_strin
|
|||||||
|
|
||||||
auto args = std::make_shared<RetryArgs>();
|
auto args = std::make_shared<RetryArgs>();
|
||||||
args->func = std::move(func);
|
args->func = std::move(func);
|
||||||
args->retry_countdown = max_attempts;
|
|
||||||
args->current_interval = initial_wait_time;
|
|
||||||
args->component = component;
|
args->component = component;
|
||||||
args->name = name_cstr ? name_cstr : ""; // Convert to std::string for RetryArgs
|
|
||||||
args->backoff_increase_factor = backoff_increase_factor;
|
|
||||||
args->scheduler = this;
|
args->scheduler = this;
|
||||||
|
args->current_interval = initial_wait_time;
|
||||||
|
args->backoff_increase_factor = backoff_increase_factor;
|
||||||
|
args->retry_countdown = max_attempts;
|
||||||
|
|
||||||
|
// Store name - either as static pointer or owned copy
|
||||||
|
if (name_cstr == nullptr || name_cstr[0] == '\0') {
|
||||||
|
// Empty or null name - use empty string literal
|
||||||
|
args->name = "";
|
||||||
|
args->name_is_dynamic = false;
|
||||||
|
} else if (is_static_string) {
|
||||||
|
// Static string - just store the pointer
|
||||||
|
args->name = name_cstr;
|
||||||
|
args->name_is_dynamic = false;
|
||||||
|
} else {
|
||||||
|
// Dynamic string - make a copy
|
||||||
|
size_t len = strlen(name_cstr);
|
||||||
|
char *copy = new char[len + 1];
|
||||||
|
memcpy(copy, name_cstr, len + 1);
|
||||||
|
args->name = copy;
|
||||||
|
args->name_is_dynamic = true;
|
||||||
|
}
|
||||||
|
|
||||||
// First execution of `func` immediately - use set_timer_common_ with is_retry=true
|
// First execution of `func` immediately - use set_timer_common_ with is_retry=true
|
||||||
|
// Pass is_static_string=true because args->name is owned by the shared_ptr<RetryArgs>
|
||||||
|
// which is captured in the lambda and outlives the SchedulerItem
|
||||||
this->set_timer_common_(
|
this->set_timer_common_(
|
||||||
component, SchedulerItem::TIMEOUT, false, &args->name, 0, [args]() { retry_handler(args); },
|
component, SchedulerItem::TIMEOUT, true, args->name, 0, [args]() { retry_handler(args); },
|
||||||
/* is_retry= */ true);
|
/* is_retry= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user