|
|
@@ -8,6 +8,7 @@
|
|
|
#include <boost/iterator/counting_iterator.hpp>
|
|
|
|
|
|
#include <fmt/format.h>
|
|
|
+#include <spdlog/spdlog.h>
|
|
|
|
|
|
#include <algorithm>
|
|
|
#include <coroutine>
|
|
|
@@ -25,22 +26,27 @@ namespace sophiar {
|
|
|
|
|
|
struct sophiar_manager::impl {
|
|
|
|
|
|
- using mode_index_type = uint8_t;
|
|
|
+ using config_index_type = uint16_t;
|
|
|
+ config_index_type next_config_index = 0;
|
|
|
|
|
|
struct config_info {
|
|
|
nlohmann::json config;
|
|
|
- timestamp_type update_ts;
|
|
|
+ int16_t ref_count = 0;
|
|
|
};
|
|
|
|
|
|
- using mode_config_pool_type = std::unordered_map<mode_index_type, config_info>;
|
|
|
+ using config_pool_type = std::unordered_map<config_index_type, config_info>;
|
|
|
+ config_pool_type config_pool;
|
|
|
+
|
|
|
+ using mode_index_type = uint8_t;
|
|
|
+ using mode_config_pool_type = std::unordered_map<mode_index_type, config_index_type>;
|
|
|
|
|
|
using obj_type_index_type = uint8_t;
|
|
|
using obj_factory_func_pool_type = named_vector<obj_type_index_type, obj_factory_func_type>;
|
|
|
|
|
|
struct obj_info {
|
|
|
sophiar_obj *ptr;
|
|
|
- timestamp_type last_init_config_ts;
|
|
|
- timestamp_type last_start_config_ts;
|
|
|
+ config_index_type last_init_config_index;
|
|
|
+ config_index_type last_start_config_index;
|
|
|
mode_config_pool_type init_config_pool;
|
|
|
mode_config_pool_type start_config_pool;
|
|
|
};
|
|
|
@@ -99,6 +105,11 @@ namespace sophiar {
|
|
|
mode_index_type current_mode = 0; // all_down
|
|
|
mode_pool_type mode_pool;
|
|
|
|
|
|
+ impl() {
|
|
|
+ config_pool[next_config_index++] =
|
|
|
+ config_info{.config={}, .ref_count=1}; // default empty config
|
|
|
+ }
|
|
|
+
|
|
|
std::string get_obj_name_by_ptr(sophiar_obj *obj) const {
|
|
|
assert(obj_ptr_index_map.contains(obj));
|
|
|
auto obj_index = obj_ptr_index_map.at(obj);
|
|
|
@@ -119,6 +130,26 @@ namespace sophiar {
|
|
|
return fmt::format("slot://{}/{}", slot_obj_name, slot_name);
|
|
|
}
|
|
|
|
|
|
+ static auto get_connection_uri(const signal_index_type signal_index,
|
|
|
+ const slot_index_type slot_index) {
|
|
|
+ return fmt::format("connection://{}/{}", signal_index, slot_index);
|
|
|
+ }
|
|
|
+
|
|
|
+ void acquire_config(config_index_type config_index) {
|
|
|
+ assert(config_pool.contains(config_index));
|
|
|
+ ++config_pool.at(config_index).ref_count;
|
|
|
+ }
|
|
|
+
|
|
|
+ void release_config(config_index_type config_index) {
|
|
|
+ assert(config_pool.contains(config_index));
|
|
|
+ auto ref_count_after = --config_pool.at(config_index).ref_count;
|
|
|
+ assert(ref_count_after >= 0);
|
|
|
+ if (ref_count_after == 0) { // delete config
|
|
|
+ config_pool.erase(config_index);
|
|
|
+ assert(!config_pool.contains(config_index));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
void enable_connection(connection_index_type conn_index) {
|
|
|
auto &conn_info = connection_pool[conn_index];
|
|
|
assert(!conn_info.is_connected);
|
|
|
@@ -139,6 +170,8 @@ namespace sophiar {
|
|
|
conn_info.is_direct_connected = false;
|
|
|
conn_info.slot_iter = slot_info.used_slot_pool.begin();
|
|
|
}
|
|
|
+ SPDLOG_DEBUG("Connection [uri = {}] is enabled.",
|
|
|
+ get_connection_uri(conn_info.signal_index, conn_info.slot_index));
|
|
|
conn_info.is_connected = true;
|
|
|
}
|
|
|
|
|
|
@@ -147,13 +180,15 @@ namespace sophiar {
|
|
|
assert(conn_info.is_connected);
|
|
|
auto &slot_info = slot_pool[conn_info.slot_index];
|
|
|
if (conn_info.is_direct_connected) {
|
|
|
- slot_info.direct_slot->unlink();
|
|
|
+ slot_info.direct_slot->disconnect();
|
|
|
} else {
|
|
|
auto target_slot = *(conn_info.slot_iter);
|
|
|
- target_slot->unlink();
|
|
|
+ target_slot->disconnect();
|
|
|
slot_info.used_slot_pool.erase(conn_info.slot_iter);
|
|
|
slot_info.free_slot_pool.push(target_slot);
|
|
|
}
|
|
|
+ SPDLOG_DEBUG("Connection [uri = {}] is disabled.",
|
|
|
+ get_connection_uri(conn_info.signal_index, conn_info.slot_index));
|
|
|
conn_info.is_connected = false;
|
|
|
}
|
|
|
|
|
|
@@ -161,6 +196,9 @@ namespace sophiar {
|
|
|
auto &mode_info = mode_pool[mode_index];
|
|
|
using state_type = tristate_obj::state_type;
|
|
|
|
|
|
+ SPDLOG_INFO("Try switch to mode {}...",
|
|
|
+ mode_pool.to_name_by_index(mode_index));
|
|
|
+
|
|
|
// 停止不需要的对象
|
|
|
for (obj_index_type obj_index = 0; obj_index < obj_pool.size(); ++obj_index) {
|
|
|
auto tristate_ptr = get_tristate_ptr(obj_index);
|
|
|
@@ -207,13 +245,14 @@ namespace sophiar {
|
|
|
|
|
|
assert(obj_info.init_config_pool.contains(mode_index));
|
|
|
assert(obj_info.start_config_pool.contains(mode_index));
|
|
|
- auto &init_config = obj_info.init_config_pool.at(mode_index);
|
|
|
- auto &start_config = obj_info.start_config_pool.at(mode_index);
|
|
|
+ auto init_config_index = obj_info.init_config_pool.at(mode_index);
|
|
|
+ auto start_config_index = obj_info.start_config_pool.at(mode_index);
|
|
|
|
|
|
// check if start config is updated
|
|
|
if (tristate_ptr->get_state() == state_type::RUNNING) {
|
|
|
- assert(obj_info.last_start_config_ts <= start_config.update_ts);
|
|
|
- if (obj_info.last_start_config_ts < start_config.update_ts) {
|
|
|
+ if (obj_info.last_start_config_index != start_config_index) {
|
|
|
+ SPDLOG_DEBUG("New start config found for object [name = {}].",
|
|
|
+ obj_pool.to_name_by_index(obj_index));
|
|
|
co_await tristate_ptr->stop();
|
|
|
assert(tristate_ptr->is_stable());
|
|
|
}
|
|
|
@@ -223,8 +262,9 @@ namespace sophiar {
|
|
|
if (tristate_ptr->get_state() != state_type::INITIAL) {
|
|
|
assert(tristate_ptr->get_state() == state_type::PENDING ||
|
|
|
tristate_ptr->get_state() == state_type::RUNNING);
|
|
|
- assert(obj_info.last_init_config_ts <= init_config.update_ts);
|
|
|
- if (obj_info.last_init_config_ts < init_config.update_ts) {
|
|
|
+ if (obj_info.last_init_config_index != init_config_index) {
|
|
|
+ SPDLOG_DEBUG("New init config found for object [name = {}].",
|
|
|
+ obj_pool.to_name_by_index(obj_index));
|
|
|
co_await tristate_ptr->reset();
|
|
|
assert(tristate_ptr->is_stable());
|
|
|
}
|
|
|
@@ -235,13 +275,15 @@ namespace sophiar {
|
|
|
|
|
|
// if not initialized, make it to be pending
|
|
|
if (tristate_ptr->get_state() == state_type::INITIAL) {
|
|
|
- CO_ENSURE(tristate_ptr->init(init_config.config))
|
|
|
- obj_info.last_init_config_ts = init_config.update_ts;
|
|
|
+ assert(config_pool.contains(init_config_index));
|
|
|
+ CO_ENSURE(tristate_ptr->init(config_pool.at(init_config_index).config))
|
|
|
+ obj_info.last_init_config_index = init_config_index;
|
|
|
}
|
|
|
|
|
|
assert(tristate_ptr->get_state() == state_type::PENDING);
|
|
|
- CO_ENSURE(tristate_ptr->start(start_config.config))
|
|
|
- obj_info.last_start_config_ts = start_config.update_ts;
|
|
|
+ assert(config_pool.contains(start_config_index));
|
|
|
+ CO_ENSURE(tristate_ptr->start(config_pool.at(start_config_index).config))
|
|
|
+ obj_info.last_start_config_index = start_config_index;
|
|
|
assert(tristate_ptr->get_state() == state_type::RUNNING);
|
|
|
}
|
|
|
|
|
|
@@ -251,9 +293,13 @@ namespace sophiar {
|
|
|
awaitable<bool> switch_mode_impl(mode_index_type target_mode) { // 尝试切换模式,如果失败就降级
|
|
|
bool ok = co_await try_switch_mode(target_mode);
|
|
|
if (ok) co_return true;
|
|
|
+ SPDLOG_ERROR("Switch to target mode {} failed, degrading...",
|
|
|
+ mode_pool.to_name_by_index(target_mode));
|
|
|
for (auto degrade_mode: mode_pool[target_mode].degrade_list) {
|
|
|
ok = co_await try_switch_mode(degrade_mode);
|
|
|
if (ok) break;
|
|
|
+ SPDLOG_ERROR("Switch to degrade mode {} failed, degrading...",
|
|
|
+ mode_pool.to_name_by_index(degrade_mode));
|
|
|
}
|
|
|
co_return false;
|
|
|
}
|
|
|
@@ -376,10 +422,12 @@ namespace sophiar {
|
|
|
}
|
|
|
assert(config_json.contains("config"));
|
|
|
auto &init_config = config_json["config"];
|
|
|
+ auto cur_config_index = next_config_index++;
|
|
|
+ auto &config_info = config_pool[cur_config_index];
|
|
|
+ config_info.config = init_config;
|
|
|
for (auto mode_index: mode_list) {
|
|
|
- auto &config_info = obj_info.init_config_pool[mode_index];
|
|
|
- config_info.update_ts = current_ts;
|
|
|
- config_info.config = init_config;
|
|
|
+ obj_info.init_config_pool[mode_index] = cur_config_index;
|
|
|
+ acquire_config(cur_config_index);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -394,10 +442,12 @@ namespace sophiar {
|
|
|
}
|
|
|
assert(config_json.contains("config"));
|
|
|
auto &start_config = config_json["config"];
|
|
|
+ auto cur_config_index = next_config_index++;
|
|
|
+ auto &config_info = config_pool[cur_config_index];
|
|
|
+ config_info.config = start_config;
|
|
|
for (auto mode_index: mode_list) {
|
|
|
- auto &config_info = obj_info.start_config_pool[mode_index];
|
|
|
- config_info.update_ts = current_ts;
|
|
|
- config_info.config = start_config;
|
|
|
+ obj_info.start_config_pool[mode_index] = cur_config_index;
|
|
|
+ acquire_config(cur_config_index);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -405,15 +455,13 @@ namespace sophiar {
|
|
|
for (auto mode_index: enabled_modes) {
|
|
|
if (!obj_info.init_config_pool.contains(mode_index)) {
|
|
|
// TODO show log
|
|
|
- auto &config_info = obj_info.init_config_pool[mode_index];
|
|
|
- config_info.update_ts = current_ts;
|
|
|
- config_info.config = {};
|
|
|
+ obj_info.init_config_pool[mode_index] = 0; // empty config
|
|
|
+ acquire_config(0);
|
|
|
}
|
|
|
if (!obj_info.start_config_pool.contains(mode_index)) {
|
|
|
// TODO show log
|
|
|
- auto &config_info = obj_info.start_config_pool[mode_index];
|
|
|
- config_info.update_ts = current_ts;
|
|
|
- config_info.config = {};
|
|
|
+ obj_info.start_config_pool[mode_index] = 0; // empty config
|
|
|
+ acquire_config(0);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -458,7 +506,7 @@ namespace sophiar {
|
|
|
auto slot_uri = get_slot_uri(slot_obj_name, slot_name);
|
|
|
auto signal_index = signal_pool.to_index_by_name(signal_uri);
|
|
|
auto slot_index = slot_pool.to_index_by_name(slot_uri);
|
|
|
- auto conn_uri = fmt::format("connection://{}/{}", signal_index, slot_index);
|
|
|
+ auto conn_uri = get_connection_uri(signal_index, slot_index);
|
|
|
auto conn_index = connection_pool.contains(conn_uri) ?
|
|
|
connection_pool.to_index_by_name(conn_uri) :
|
|
|
connection_pool.new_elem(conn_uri);
|
|
|
@@ -511,6 +559,11 @@ namespace sophiar {
|
|
|
co_return co_await pimpl->switch_mode_impl(mode_index);
|
|
|
}
|
|
|
|
|
|
+ std::string sophiar_manager::get_object_name(sophiar_obj *obj) const {
|
|
|
+ auto obj_index = pimpl->obj_ptr_index_map.at(obj);
|
|
|
+ return pimpl->obj_pool.to_name_by_index(obj_index);
|
|
|
+ }
|
|
|
+
|
|
|
sophiar_manager::~sophiar_manager() = default;
|
|
|
|
|
|
}
|