@@ -25,6 +25,45 @@ using std::unordered_map;
2525using std::unordered_set;
2626using std::vector;
2727
28+ namespace facebook {
29+ namespace memcache {
30+ namespace options {
31+
32+ unordered_map<string, string> parseStringMapOption (
33+ const string& str,
34+ StringMapParseOptions parseOptions) {
35+ vector<folly::StringPiece> pairs;
36+ folly::split (' ,' , str, pairs);
37+ unordered_map<string, string> result;
38+ for (const auto & pair : pairs) {
39+ if (pair.empty ()) {
40+ checkLogic (
41+ parseOptions.ignoreEmptyPairs ,
42+ " Invalid string map pair: '{}'. Expected name:value." ,
43+ pair);
44+ continue ;
45+ }
46+ const auto delimiter = pair.find (' :' );
47+ checkLogic (
48+ delimiter != string::npos,
49+ " Invalid string map pair: '{}'. Expected name:value." ,
50+ pair);
51+ auto key = substituteTemplates (pair.subpiece (0 , delimiter).str ());
52+ checkLogic (!key.empty (), " Empty key in string map pair: '{}'." , pair);
53+ auto value = substituteTemplates (pair.subpiece (delimiter + 1 ).str ());
54+ if (parseOptions.overwriteDuplicateKeys ) {
55+ result.insert_or_assign (std::move (key), std::move (value));
56+ } else {
57+ result.emplace (std::move (key), std::move (value));
58+ }
59+ }
60+ return result;
61+ }
62+
63+ } // namespace options
64+ } // namespace memcache
65+ } // namespace facebook
66+
2867namespace folly {
2968
3069namespace {
@@ -83,19 +122,7 @@ typename std::enable_if<
83122 std::is_same<unordered_map<string, string>, Tgt>::value,
84123 unordered_map<string, string>>::type
85124to (const string& s) {
86- vector<folly::StringPiece> pairs;
87- folly::split (' ,' , s, pairs);
88- unordered_map<string, string> result;
89- for (const auto & it : pairs) {
90- string key;
91- string value;
92- facebook::memcache::checkLogic (
93- folly::split<false >(' :' , it, key, value) && !key.empty (),
94- " Invalid string map pair: '{}'. Expected name:value." ,
95- it);
96- result.emplace (std::move (key), std::move (value));
97- }
98- return result;
125+ return facebook::memcache::options::parseStringMapOption (s);
99126}
100127
101128} // namespace folly
@@ -200,20 +227,25 @@ vector<McrouterOptionError> McrouterOptionsBase::updateFromDict(
200227 const boost::any& value) {
201228 auto it = new_opts.find (name);
202229 if (it != new_opts.end ()) {
203- auto subValue = options::substituteTemplates (it->second );
230+ std::optional<string> substitutedValue;
231+ const string* subValue = &it->second ;
232+ if (type != McrouterOptionData::Type::string_map) {
233+ substitutedValue = options::substituteTemplates (it->second );
234+ subValue = &*substitutedValue;
235+ }
204236 try {
205- fromString (subValue, value);
237+ fromString (* subValue, value);
206238 } catch (const std::exception& ex) {
207239 McrouterOptionError e;
208240 e.requestedName = name;
209- e.requestedValue = subValue;
241+ e.requestedValue = * subValue;
210242 e.errorMsg = " couldn't convert value to " + optionTypeToString (type) +
211243 " . Exception: " + ex.what ();
212244 errors.push_back (std::move (e));
213245 } catch (...) {
214246 McrouterOptionError e;
215247 e.requestedName = name;
216- e.requestedValue = subValue;
248+ e.requestedValue = * subValue;
217249 e.errorMsg = " couldn't convert value to " + optionTypeToString (type);
218250 errors.push_back (std::move (e));
219251 }
@@ -252,10 +284,16 @@ vector<McrouterOptionMismatch> McrouterOptionsBase::compare(
252284 " Not found in luna_opts, with type " + optionTypeToString (type);
253285 errors.push_back (std::move (e));
254286 } else {
255- auto subValue = options::substituteTemplates (it->second );
287+ std::optional<string> substitutedValue;
288+ const string* subValue = &it->second ;
289+ if (type != McrouterOptionData::Type::string_map) {
290+ substitutedValue = options::substituteTemplates (it->second );
291+ subValue = &*substitutedValue;
292+ }
256293
257294 try {
258295 auto currValue = toString (value);
296+ auto displayedNewValue = *subValue;
259297 // config_params is a string of comma-separated key-value pairs
260298 // e.g. "key1:value1,key2:value2", and are stored as
261299 // McrouterOptionData::Type::string_map. We need to compare as maps
@@ -269,17 +307,18 @@ vector<McrouterOptionMismatch> McrouterOptionsBase::compare(
269307 if (oldValuePtr == nullptr ) {
270308 throw std::runtime_error (" could not cast config_params to a map" );
271309 }
272- fromString (subValue, newValue);
310+ fromString (*subValue, newValue);
311+ displayedNewValue = folly::to<string>(newValueMap);
273312 isSame = **boost::any_cast<unordered_map<string, string>*>(
274313 &newValue) == **oldValuePtr;
275314 } else {
276- isSame = currValue == subValue;
315+ isSame = currValue == * subValue;
277316 }
278317 if (!isSame) {
279318 McrouterOptionMismatch e;
280319 e.optionName = name;
281320 e.lunaValue = it->second ;
282- e.errorMsg = " luna value " + subValue +
321+ e.errorMsg = " luna value " + displayedNewValue +
283322 " and current mcrouter_options value " + currValue +
284323 " are different" ;
285324 errors.push_back (std::move (e));
0 commit comments