-
Notifications
You must be signed in to change notification settings - Fork 833
Add nexthop strategy plugins #7023
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
64733d7
to
8f02d13
Compare
const time_t now = 0) = 0; | ||
virtual ~NHHealthStatus() {} | ||
}; | ||
class TSNextHopSelectionStrategy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this make the plugin API require C++?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can move this to include/tscpp
. Is that ok?
Sort of. TSNextHopSelectionStrategy
is used by the Remap hook TSRemapInitStrategy
, not in InkApi.cc. A Remap plugin can still be C and just not implement that function.
Likewise, TSHttpTxnParentResult(G|S)et
in InkApi.cc uses a TSParentResult
, which has C++ stuff in it. I just exposed that struct to the API, I didn't create it. If someone doesn't need to call that function, if I move parentresult.h
to include/tscpp
, they can write a C plugin and just not call the functions that use it.
Is that ok? Or is there a better way?
include/ts/parentresult.h
Outdated
int port; | ||
bool retry; | ||
TSParentResultType result; | ||
bool chash_init[TS_MAX_GROUP_RINGS] = {false}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, is this C++? If so, std::bitset
is a better choice here, otherwise I'd look at making this a bit mask object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the object is C++, unfortunately.
This is an API version of a core struct that already exists. If it's changed here, moving the data between the API and core will have to translate between them, and will probably be less efficient.
Alternatively, I could change it in core. It looks like that wouldn't be too invasive.
I haven't benchmarked, but it was my understanding that std::bitset is optimized for space, and is often less performant than bool[]
or bitmasking. Notwithstanding, I'd still prefer to do a bitmask, because the struct only has one C++ member, and I'd like to move it in the direction of C for the sake of the API.
constexpr std::string_view hash_key_cache = "cache_key"; | ||
|
||
static HostRecord * | ||
chash_lookup(std::shared_ptr<ATSConsistentHash> ring, uint64_t hash_key, ATSConsistentHashIter *iter, bool *wrapped, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more than enough state to justify an iterator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was moved/copied from core. Not sure what you mean? It takes a ATSConsistentHashIter
, that's what that is. You mean taking all these args and wrapping them up in an iterator object, so things would call chIter->begin()
, ++chIter
, etc?
plugins/experimental/nexthop_strategy_consistenthash/consistenthash.cc
Outdated
Show resolved
Hide resolved
HostRecord *p = host_groups[i][j].get(); | ||
// need to copy the 'hash_string' or 'hostname' cstring to 'name' for insertion into ATSConsistentHash. | ||
if (!p->hash_string.empty()) { | ||
p->name = const_cast<char *>(p->hash_string.c_str()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is const_cast
really required here? It's a bit risky.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also copied from core. Yeah, because HostRecord.name
is not const. I was told it couldn't be for reasons, and that it would never be changed. Likewise, I was assured hash_string would always outlive it, making returning the c_str safe.
I can try to verify those things, but it would take some time. FWIW I certainly don't like it either, but didn't see an obvious alternative.
plugins/experimental/nexthop_strategy_consistenthash/consistenthash.cc
Outdated
Show resolved
Hide resolved
} | ||
|
||
void | ||
ParentResult::copyTo(TSParentResult *r) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason these aren't assignment operators?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh, I lean against obfuscating nontrivial copies, and these funcs are just complex enough to be nontrivial. I can change it if you want / if overriding assignment is the idiom in ATS
char tmpbuf[2048]; | ||
ink_zero(tmpbuf); | ||
TSNextHopSelectionStrategy *strategy_raw = nullptr; | ||
if (init_strategy_cb(strategy_raw, ih, tmpbuf, sizeof(tmpbuf) - 1) != TS_SUCCESS) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does strategy_raw
become not nullptr
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
init_strategy_cb
is TSRemapInitStrategy
, which takes a TSNextHopSelectionStrategy *&
. A plugin sets that pointer-ref.
trafficserver/plugins/experimental/nexthop_strategy_consistenthash/plugin_consistenthash.cc
Line 74 in 00e236d
strategy = static_cast<TSNextHopSelectionStrategy *>(ih); |
-0, AFAIK the general plugin design is to use event handlers. Which I realized will take a lot more work but also simplify the API and the HttpSM quite a bit in the end. I hope we can move towards that once Susan gets the ConnectionSM refactored. |
virtual ~NHPluginStrategy() {} | ||
virtual void findNextHop(TSHttpTxn txnp, time_t now = 0) = 0; | ||
virtual void markNextHop(TSHttpTxn txnp, const char *hostname, const int port, const NHCmd status, const time_t now = 0) = 0; | ||
virtual bool nextHopExists(TSHttpTxn txnp) = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really useful? Why not have findNextHop
return bool
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
findNextHop
modifies the state to be the next parent; nextHopExists
returns without modifying state.
I'd be a big +1 on making findNextHop
return and be a pure function. But that'd require refactoring how Strategies work and are called in core. Which I'm guessing itself is a reflection of how ParentSelection always did it.
bool wrap_around; | ||
bool mapWrapped[2]; | ||
int last_lookup; | ||
ATSConsistentHashIter chashIter[TS_MAX_GROUP_RINGS]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the hash values and iterators needed in this result structure? Is this intended as a state object and not just a result?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's a state object. Used by both ParentSelection and Strategies in core (or rather, copied to an identical structure in core).
I.e.
https://github.com/apache/trafficserver/blob/786463/proxy/ParentConsistentHash.cc#L110
https://github.com/apache/trafficserver/blob/786463/proxy/http/remap/NextHopConsistentHash.cc#L335
3f9cd6e
to
e75a4a5
Compare
4c579f3
to
e102d13
Compare
} | ||
|
||
for (unsigned int i = 0; i < strategies.size(); ++i) { | ||
YAML::Node strategy = strategies[i]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you considered following this for custom Data Types like TSNextHopSelectionStrategy
?
Adds a remap plugin hook to add a strategy object, and moves and adds other necessary API symbols necessary to implement strategies in plugins. Also adds an example strategy plugin.
Also changes the HostStatus and what it exposes, and changes char* to also take the len to make string_view construction faster/easier.
e102d13
to
9412a14
Compare
Changing back to a draft: I have an idea to get the best of both worlds, small core changes like this PR, but also powerful and with real continuations, hooks, etc. I'm not 100% sure the idea will work. If it does, I'll close those. If not, I'll un-draft it. |
Closing in favor of #7467 |
Adds a remap plugin hook to add a nexthop strategy object, and moves and adds other necessary API symbols necessary to implement strategies in plugins.
Also adds an example nexthop strategy plugin.
This adds the following to the API:
I tried to minimize API changes, but I didn't see a way to do it any smaller.
The example plugin is also a lot of duplication from the core ConsistentHash strategy. I didn't see a reasonable way to reduce that either, while keeping the ConsistentHash strategy in core for now.
I'm definitely open to suggestions.