Add nexthop strategy plugins#7023
Conversation
64733d7 to
8f02d13
Compare
| const time_t now = 0) = 0; | ||
| virtual ~NHHealthStatus() {} | ||
| }; | ||
| class TSNextHopSelectionStrategy |
There was a problem hiding this comment.
Does this make the plugin API require C++?
There was a problem hiding this comment.
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?
| int port; | ||
| bool retry; | ||
| TSParentResultType result; | ||
| bool chash_init[TS_MAX_GROUP_RINGS] = {false}; |
There was a problem hiding this comment.
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.
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.
This is more than enough state to justify an iterator.
There was a problem hiding this comment.
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?
| 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.
Is const_cast really required here? It's a bit risky.
There was a problem hiding this comment.
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.
| } | ||
|
|
||
| void | ||
| ParentResult::copyTo(TSParentResult *r) |
There was a problem hiding this comment.
Any reason these aren't assignment operators?
There was a problem hiding this comment.
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.
How does strategy_raw become not nullptr?
There was a problem hiding this comment.
init_strategy_cb is TSRemapInitStrategy, which takes a TSNextHopSelectionStrategy *&. A plugin sets that pointer-ref.
|
-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.
Is this really useful? Why not have findNextHop return bool?
There was a problem hiding this comment.
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.
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.
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.
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.