clboss/Boss/Mod/RebalanceModeManager.cpp
Ken Sedgwick 602aed25b6
Add the xrebalance track to the rebalance-mode and askrene-layer infra
Re-introduces the second rebalancing track (Track B, "xrebalance": the
circular askrene min-cost-flow rebalancer) into the shared selection and
layer infrastructure, so it can coexist with the classic track in one
binary and be chosen at runtime.

  - Boss::RebalanceMode gains the xrebalance value (+ to_string /
    from_string arms and the doc bullet), selectable via
    clboss-rebalance-mode alongside classic and off.
  - Boss::Mod::AskreneLayer gains xrebalance_layer_name
    ("clboss-xrebalance"), the persistent askrene layer the xrebalance
    code paths accumulate probe knowledge into.  Kept distinct from the
    "clboss" layer so the two tracks' learning does not commingle while
    both run side by side.
  - clboss-rebalance-mode help text now lists xrebalance.

This is only the seam: nothing drives xrebalance yet.  The XMoveFunds
primitive and the XRebalancer driver land in following commits.  The
classic rebalancers already gate on mode == classic, so selecting
xrebalance simply quiesces them (like off) until the driver arrives.
2026-07-02 18:38:19 -07:00

129 lines
3.4 KiB
C++

#include"Boss/Mod/RebalanceModeManager.hpp"
#include"Boss/Msg/Manifestation.hpp"
#include"Boss/Msg/ManifestOption.hpp"
#include"Boss/Msg/Option.hpp"
#include"Boss/Msg/OptionType.hpp"
#include"Boss/Msg/ProvideStatus.hpp"
#include"Boss/Msg/RequestRebalanceMode.hpp"
#include"Boss/Msg/ResponseRebalanceMode.hpp"
#include"Boss/Msg/SolicitStatus.hpp"
#include"Boss/RebalanceMode.hpp"
#include"Boss/log.hpp"
#include"Ev/Io.hpp"
#include"Json/Out.hpp"
#include"S/Bus.hpp"
#include"Util/make_unique.hpp"
namespace {
/* Single dynamic option: the config file sets the startup default and
* `setconfig clboss-rebalance-mode <mode>` switches it at runtime. */
auto const option_name = std::string("clboss-rebalance-mode");
}
namespace Boss { namespace Mod {
class RebalanceModeManager::Impl {
private:
S::Bus& bus;
RebalanceMode mode;
void start() {
mode = default_rebalance_mode;
bus.subscribe<Msg::Manifestation
>([this](Msg::Manifestation const& _) {
return bus.raise(Msg::ManifestOption{
option_name,
Msg::OptionType_String,
Json::Out::direct(std::string(
rebalance_mode_to_string(
default_rebalance_mode
)
)),
"Rebalancer mode: \"classic\" (the original "
"rebalancer), \"xrebalance\" (the circular askrene "
"rebalancer, tuned by clboss-xrebalance-*), or "
"\"off\" (disable rebalancing). "
" Set in the config for the startup default or "
"at runtime with "
"`setconfig clboss-rebalance-mode <mode>`.",
true /* dynamic: runtime-settable via setconfig */
});
});
bus.subscribe<Msg::Option
>([this](Msg::Option const& o) {
if (o.name != option_name)
return Ev::lift();
auto s = std::string(o.value);
auto m = RebalanceMode();
if (!rebalance_mode_from_string(s, m)) {
/* No double quotes in the message:
* lightningd forwards plugin setconfig
* errors as the raw JSON-escaped token
* (plugin_setconfig_done uses the wire
* bytes verbatim), so embedded quotes
* reach the user doubled-escaped. */
o.reject( option_name + ": unrecognized "
"value '" + s + "'");
return Boss::log( bus, Error
, "RebalanceModeManager: "
"ignoring unrecognized "
"%s value \"%s\"; "
"keeping \"%s\"."
, option_name.c_str()
, s.c_str()
, rebalance_mode_to_string(mode)
);
}
if (m == mode)
return Ev::lift();
mode = m;
return Boss::log( bus, Info
, "RebalanceModeManager: "
"mode set to \"%s\"."
, rebalance_mode_to_string(mode)
);
});
bus.subscribe<Msg::RequestRebalanceMode
>([this](Msg::RequestRebalanceMode const& m) {
return bus.raise(Msg::ResponseRebalanceMode{
m.requester, mode
});
});
bus.subscribe<Msg::SolicitStatus
>([this](Msg::SolicitStatus const& _) {
auto out = Json::Out();
out.start_object()
.field("mode", std::string(rebalance_mode_to_string(mode)))
.end_object()
;
return bus.raise(Msg::ProvideStatus{
"rebalance_mode", std::move(out)
});
});
}
public:
Impl() =delete;
Impl(Impl&&) =delete;
Impl(Impl const&) =delete;
explicit
Impl(S::Bus& bus_) : bus(bus_) {
start();
}
};
RebalanceModeManager::RebalanceModeManager(RebalanceModeManager&&) =default;
RebalanceModeManager::~RebalanceModeManager() =default;
RebalanceModeManager::RebalanceModeManager(S::Bus& bus)
: pimpl(Util::make_unique<Impl>(bus)) { }
}}