-
Notifications
You must be signed in to change notification settings - Fork 620
RFC: Support connection-linked helper notes #2399
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,13 +7,17 @@ | |
| */ | ||
|
|
||
| #include "squid.h" | ||
| #include "base/CharacterSet.h" | ||
| #include "base/PackableStream.h" | ||
| #include "cache_cf.h" | ||
| #include "ConfigParser.h" | ||
| #include "debug/Stream.h" | ||
| #include "globals.h" | ||
| #include "helper/ChildConfig.h" | ||
| #include "Parsing.h" | ||
| #include "sbuf/SBuf.h" | ||
| #include "parser/Tokenizer.h" | ||
| #include "sbuf/List.h" | ||
| #include "Store.h" | ||
|
|
||
| #include <cstring> | ||
|
|
||
|
|
@@ -72,7 +76,7 @@ Helper::ChildConfig::needNew() const | |
| void | ||
| Helper::ChildConfig::parseConfig() | ||
| { | ||
| char const *token = ConfigParser::NextToken(); | ||
| char *token = ConfigParser::NextToken(); | ||
|
|
||
| if (!token) { | ||
| self_destruct(); | ||
|
|
@@ -89,22 +93,23 @@ Helper::ChildConfig::parseConfig() | |
| } | ||
|
|
||
| /* Parse extension options */ | ||
| for (; (token = ConfigParser::NextToken()) ;) { | ||
| if (strncmp(token, "startup=", 8) == 0) { | ||
| n_startup = xatoui(token + 8); | ||
| } else if (strncmp(token, "idle=", 5) == 0) { | ||
| n_idle = xatoui(token + 5); | ||
| char *value; | ||
| while (ConfigParser::NextKvPair(token, value)) { | ||
| if (strncmp(token, "startup", 7) == 0) { | ||
| n_startup = xatoui(value); | ||
| } else if (strncmp(token, "idle", 4) == 0) { | ||
| n_idle = xatoui(value); | ||
| if (n_idle < 1) { | ||
| debugs(0, DBG_CRITICAL, "WARNING: OVERRIDE: Using idle=0 for helpers causes request failures. Overriding to use idle=1 instead."); | ||
| n_idle = 1; | ||
| } | ||
| } else if (strncmp(token, "concurrency=", 12) == 0) { | ||
| concurrency = xatoui(token + 12); | ||
| } else if (strncmp(token, "queue-size=", 11) == 0) { | ||
| queue_size = xatoui(token + 11); | ||
| } else if (strncmp(token, "concurrency", 11) == 0) { | ||
| concurrency = xatoui(value); | ||
| } else if (strncmp(token, "queue-size", 10) == 0) { | ||
| queue_size = xatoui(value); | ||
| defaultQueueSize = false; | ||
| } else if (strncmp(token, "on-persistent-overload=", 23) == 0) { | ||
| const SBuf action(token + 23); | ||
| } else if (strncmp(token, "on-persistent-overload", 22) == 0) { | ||
| const SBuf action(value); | ||
| if (action.cmp("ERR") == 0) | ||
| onPersistentOverload = actErr; | ||
| else if (action.cmp("die") == 0) | ||
|
|
@@ -114,8 +119,10 @@ Helper::ChildConfig::parseConfig() | |
| self_destruct(); | ||
| return; | ||
| } | ||
| } else if (strncmp(token, "reservation-timeout=", 20) == 0) | ||
| reservationTimeout = xatoui(token + 20); | ||
| } else if (strncmp(token, "reservation-timeout", 19) == 0) | ||
| reservationTimeout = xatoui(value); | ||
| else if (strncmp(token, "connection-notes", 16) == 0) | ||
| parseNotesList(SBuf(value)); | ||
| else { | ||
| debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Undefined option: " << token << "."); | ||
| self_destruct(); | ||
|
|
@@ -139,3 +146,56 @@ Helper::ChildConfig::parseConfig() | |
| queue_size = 2 * n_max; | ||
| } | ||
|
|
||
| /// parses comma-separated list of key names to be | ||
| /// treated like clt_conn_tag | ||
| void | ||
| Helper::ChildConfig::parseNotesList(const SBuf &buf) | ||
| { | ||
| ::Parser::Tokenizer tok(buf); | ||
|
|
||
| static const CharacterSet delims("comma", ","); | ||
| SBuf item; | ||
| while (tok.token(item, delims)) { | ||
| static const SBuf wsp(" "); | ||
| item.trim(wsp); | ||
| if (!item.isEmpty()) | ||
| clientConnectionTags.emplace_back(item); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please refuse configurations with duplicate names because they may be dangerous typos.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, though I do not see what danger there is. What are you thinking can happen? |
||
| } | ||
| } | ||
|
|
||
| void | ||
| Helper::ChildConfig::printConfig(StoreEntry *e, const char *directive) | ||
| { | ||
| PackableStream os(*e); | ||
| os << "\n" << directive << " " << n_max; | ||
|
|
||
| if (n_startup != 0) | ||
| os << " startup=" << n_startup; | ||
|
|
||
| if (n_idle != 0) | ||
| os << " idle=" << n_idle; | ||
|
|
||
| if (concurrency != 0) | ||
| os << " concurrency=" << concurrency; | ||
|
|
||
| if (!defaultQueueSize) | ||
| os << " queue-size=" << queue_size; | ||
|
|
||
| switch (onPersistentOverload) { | ||
| case actErr: | ||
| os << " on-persistent-overload=ERR"; | ||
| break; | ||
| case actDie: // defaults not printed | ||
| break; | ||
| } | ||
|
|
||
| if (reservationTimeout != 64) | ||
| os << " reservation-timeout=" << reservationTimeout; | ||
|
|
||
| static const SBuf comma(","); | ||
| auto cnotes = JoinContainerToSBuf(clientConnectionTags.begin(), clientConnectionTags.end(), comma); | ||
| if (cnotes.cmp("clt_conn_tags") != 0) | ||
| os << " connection-notes=\"" << cnotes << '"'; | ||
|
|
||
| os << "\n"; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,8 @@ | |
| #ifndef SQUID_SRC_HELPER_CHILDCONFIG_H | ||
| #define SQUID_SRC_HELPER_CHILDCONFIG_H | ||
|
|
||
| #include "sbuf/SBuf.h" | ||
|
|
||
| namespace Helper | ||
| { | ||
|
|
||
|
|
@@ -34,6 +36,9 @@ class ChildConfig | |
| int needNew() const; | ||
| void parseConfig(); | ||
|
|
||
| /// produce squid.conf syntax for mgr:config report | ||
| void printConfig(StoreEntry *, const char *directive); | ||
|
|
||
| /** | ||
| * Update an existing set of details with new start/max/idle/concurrent limits. | ||
| * This is for parsing new child settings into an object incrementally then updating | ||
|
|
@@ -107,13 +112,20 @@ class ChildConfig | |
|
|
||
| /// older stateful helper server reservations may be forgotten | ||
| time_t reservationTimeout = 64; // reservation-timeout | ||
|
|
||
| /// List of kv-pair keys to set as annotations of the client TCP connection. | ||
| /// Default: clt_conn_tag | ||
|
Comment on lines
+116
to
+117
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO |
||
| SBufList clientConnectionTags = { SBuf("clt_conn_tag") }; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The need to apply annotations to client-to-Squid connections goes beyond helpers. For example, ICAP/eCAP adapters and "note" ACL also set transaction annotations and would benefit from a very similar feature. Please do not place that feature code inside ChildConfig. Let ChildConfig use code defined elsewhere (e.g., AnnotationNames or even Configuration::AnnotationNames).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You propose a much different project. Any code which is shared can be moved if/when other use cases are implemented. The scope of this PR is implementing a helper API configuration option. Other components of Squid will have their own logic requirements. We should not over-engineer this. [EDIT: specifically the core logic of this PR is the code of
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SBufList optimizes insertions and deletions while preserving order and supporting duplicates. For AnnotationNames, we need to optimize search time and ban duplicates. Please use an |
||
|
|
||
| private: | ||
| void parseNotesList(const SBuf &); | ||
| }; | ||
|
|
||
| } // namespace Helper | ||
|
|
||
| /* Legacy parser interface */ | ||
| #define parse_HelperChildConfig(c) (c)->parseConfig() | ||
| #define dump_HelperChildConfig(e,n,c) storeAppendPrintf((e), "\n%s %d startup=%d idle=%d concurrency=%d\n", (n), (c).n_max, (c).n_startup, (c).n_idle, (c).concurrency) | ||
| #define dump_HelperChildConfig(e,n,c) (c).printConfig((e),(n)) | ||
| #define free_HelperChildConfig(dummy) // NO. | ||
|
|
||
| #endif /* SQUID_SRC_HELPER_CHILDCONFIG_H */ | ||
|
|
||
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.
Please use (less problematic) STL descriptions and avoid an otherwise unused type alias: