Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

Closed
wants to merge 15 commits into from

Conversation

rob05c
Copy link
Member

@rob05c rob05c commented Jul 21, 2020

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:

enum TSHostStatus
enum TSHostStatusReason
enum TSParentResultType
class TSNextHopSelectionStrategy
struct TSParentResult
const char *ParentResultStr
bool TSHostnameIsSelf(const char* hostname)
bool TSHostStatusGet(const char *hostname, TSHostStatus* status, unsigned int *reason)
void TSHostStatusSet(const char *hostname, TSHostStatus status, const unsigned int down_time, const unsigned int reason)
TSParentResult* TSHttpTxnParentResultGet(TSHttpTxn txnp)
void TSHttpTxnParentResultSet(TSHttpTxn txnp, struct TSParentResult* result)
TSReturnCode TSRemapInitStrategy(TSNextHopSelectionStrategy *&strategy, void *ih, char *errbuf, int errbuf_size)

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.

@rob05c rob05c force-pushed the nexthop-rework-retry-plus-pugins2 branch from 64733d7 to 8f02d13 Compare July 21, 2020 19:05
const time_t now = 0) = 0;
virtual ~NHHealthStatus() {}
};
class TSNextHopSelectionStrategy
Copy link
Member

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++?

Copy link
Member Author

@rob05c rob05c Aug 12, 2020

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?

int port;
bool retry;
TSParentResultType result;
bool chash_init[TS_MAX_GROUP_RINGS] = {false};
Copy link
Member

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.

Copy link
Member Author

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,
Copy link
Member

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.

Copy link
Member Author

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?

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());
Copy link
Member

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.

Copy link
Member Author

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.

}

void
ParentResult::copyTo(TSParentResult *r)
Copy link
Member

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?

Copy link
Member Author

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) {
Copy link
Member

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?

Copy link
Member Author

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.

strategy = static_cast<TSNextHopSelectionStrategy *>(ih);

@a-canary
Copy link
Collaborator

a-canary commented Oct 8, 2020

-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;
Copy link
Member

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?

Copy link
Member Author

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];
Copy link
Member

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?

Copy link
Member Author

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

@rob05c rob05c force-pushed the nexthop-rework-retry-plus-pugins2 branch from 3f9cd6e to e75a4a5 Compare October 22, 2020 15:00
@rob05c rob05c force-pushed the nexthop-rework-retry-plus-pugins2 branch 2 times, most recently from 4c579f3 to e102d13 Compare November 4, 2020 18:50
@rob05c rob05c marked this pull request as ready for review November 4, 2020 18:50
}

for (unsigned int i = 0; i < strategies.size(); ++i) {
YAML::Node strategy = strategies[i];
Copy link
Contributor

@brbzull0 brbzull0 Nov 5, 2020

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.
@rob05c rob05c force-pushed the nexthop-rework-retry-plus-pugins2 branch from e102d13 to 9412a14 Compare December 14, 2020 19:37
@bryancall bryancall marked this pull request as draft January 28, 2021 22:28
@rob05c
Copy link
Member Author

rob05c commented Jan 28, 2021

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.

@rob05c
Copy link
Member Author

rob05c commented Feb 15, 2021

Closing in favor of #7467

@rob05c rob05c closed this Feb 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants