Skip to content
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

When checking if key exists in ThreadContextStruct:putHeaders() method,should put requestHeaders in map first #26068

Merged
merged 6 commits into from
Oct 9, 2017

Conversation

hanbj
Copy link
Contributor

@hanbj hanbj commented Aug 5, 2017

1、The parameter headers does not have the same key, so the checksum doesn't make sense
2、When checking that key already exists in requestHeaders, you should first put

@elasticmachine
Copy link
Collaborator

Since this is a community submitted pull request, a Jenkins build has not been kicked off automatically. Can an Elastic organization member please verify the contents of this patch and then kick off a build manually?

@hanbj hanbj changed the title When ThreadContextStruct:putHeaders(),should put requestHeaders in map first When checking if key exists in ThreadContextStruct:putHeaders() method,should put requestHeaders in map first Aug 5, 2017
@hanbj
Copy link
Contributor Author

hanbj commented Aug 11, 2017

@cbuescher This PR has been on for a long time and hasn't been noticed. I hope the great God can review it. Thanks

@cbuescher
Copy link
Member

@hanbj Sorry, but we get to it when we get to it. 6 days isn't really that long when you consider we have over a hundred open PRs, lots of open issues. I hope you understand. In the meantime it might help to understand what problem this change is trying to solve, did you run into a problem with this? Is there an open issue this fixes?

@hanbj
Copy link
Contributor Author

hanbj commented Aug 11, 2017

@cbuescher I'm very very sorry. I didn't mean that. I'm sorry to trouble you

@cbuescher
Copy link
Member

No problem, I just wanted to explain that PRs get picked up whenever anybody has time to review them.
I saw this is a follow up to #26037, but even reading that I don't quiet get the problem this is trying to solve. It probably helps anybody who will eventually review this issue if you try to motivate the chage you propose, e.g. by explaining a bug that this fixes or any other reason you think this change is necessary.

@cbuescher
Copy link
Member

And I forgot to add, thanks for taking the time and effort to look at this and submit a PR at all ;-)

@rjernst
Copy link
Member

rjernst commented Aug 14, 2017

The change looks correct to me, but I think it needs a test (in ThreadContextTests).

@hanbj
Copy link
Contributor Author

hanbj commented Aug 15, 2017

@rjernst I add a test. Thank you.

Copy link
Member

@rjernst rjernst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the added test. I left a couple minor comments. Once those are addressed I will kick off CI (it would fail right now due to wildcard imports).

import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.sameInstance;
import static org.hamcrest.Matchers.*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you run gradle precommit? This will fail. We do not use wildcard imports.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I often use formatting shortcut keys.

assertEquals("bar", threadContext.getHeader("foo"));
try {
threadContext.putHeader(Collections.<String, String>singletonMap("foo", "boom"));
} catch (IllegalArgumentException e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use expectThrows(...) instead of try/catch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes,so much the better.

@@ -407,11 +407,10 @@ private ThreadContextStruct putHeaders(Map<String, String> headers) {
if (headers.isEmpty()) {
return this;
} else {
final Map<String, String> newHeaders = new HashMap<>();
final Map<String, String> newHeaders = new HashMap<>(this.requestHeaders);
Copy link
Member

@rjernst rjernst Aug 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized I'm unsure about this fix. The putSingleHeader below will fail if the key already exists, so anything in requestHeaders can then not be overriden. I think what we want instead is a loop over requestHeaders after the headers loop, but which uses putIfAbsent?

Copy link
Contributor Author

@hanbj hanbj Aug 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't quite catch what you mean.
First of all, I didn't submit this PR before.
1, create a new HashMap instance (newHeaders).
2, traversal parameter headers.
The two step above means check whether the headers's key if exists in newHeaders.
The parameter headers is a Map. It doesn't have the same key. Just put the data in headers into newHeaders.

What we need to do is check if the parameter headers's key already exists in requestHeaders.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this logic is not changed, the following:
newHeaders.putAll (this.requestHeaders);
requestHeaders also overwrites the same key in headers, but the user doesn't know it.
For instance:
headers: ("foo", "bar")
requestHeaders: ("foo", "boom")
After running newHeaders.putAll (this.requestHeaders);
Will become: newHeaders: ("foo", "boom")
However, the user thinks the value corresponding to the foo is bar

Copy link
Member

@rjernst rjernst Aug 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you misunderstood my comment. Look at the implementation of putSingleHeader, which is what the loop over headers calls to add each header. It will throw an exception if a key already exists. This means with your change if a key exists in requestHeaders and headers, an exception will be thrown, while before, the value from requestHeaders would have "won". The bug here is that the requestHeaders value should be the fallback, right? So then, instead of initializing the newHeaders to requestHeaders, you can iterate over requestHeaders in place of the current putAll call, and use newHeaders.putIfAbsent, so that the value would only be added if headers did not contain that key.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, you can still initialize the newHeaders to requestHeaders, but change the call to putSingleHeader to newHeaders.put. Since headers and requestHeaders are already maps, there is no possibility for duplicate keys within themselves.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know what you mean now. You don't want to thrown an exception.
I found it throw an exception in the putRequest method, So I did the same.
I've also found that in the stashAndMergeHeaders method, if a key exists in context.requestHeaders and headers, the value from requestHeaders would have "won".
I'm not sure now. I hope you can give me a conclusion. if a key exists in requestHeaders and headers, whether requestHeaders to overwrite headers or headers to overwrite requestHeaders.
Thank you.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the method takes in headers, I assume those should "win" over what was in the context headers map before. However, I did notice that in stashAndMergeHeaders, the requestHeaders are merged into the headers being passed into putHeaders, and the order is again such that requestHeaders wins over headers. @s1monw can you clarify what the original intention was here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rjernst I think the fix is good. it's really just a shortcut for a single header. I wonder if we should de-optimize and just iterate over the map and use putHeader(string,string) instead? also the test looks great

@s1monw
Copy link
Contributor

s1monw commented Sep 25, 2017

@rjernst do you want to pull this in?

@rjernst
Copy link
Member

rjernst commented Oct 6, 2017

@elasticmachine ok to test

@rjernst
Copy link
Member

rjernst commented Oct 9, 2017

Thanks @hanbj. Sorry for the long delay in merging.

rjernst pushed a commit that referenced this pull request Oct 9, 2017
Previously collisions in headers between old and new contexts could be silently ignored, allowing the original context's headers to "win". This commit fixes the headers to require they are disjoint.
jasontedor added a commit to olcbean/elasticsearch that referenced this pull request Oct 10, 2017
* master: (22 commits)
  Allow only a fixed-size receive predictor (elastic#26165)
  Add Homebrew instructions to getting started
  ingest: Fix bug that prevent date_index_name processor from accepting timestamps specified as a json number
  Scripting: Fix expressions to temporarily support filter scripts (elastic#26824)
  Docs: Add note to contributing docs warning against tool based refactoring (elastic#26936)
  Fix thread context handling of headers overriding (elastic#26068)
  SearchWhileCreatingIndexIT: remove usage of _only_nodes
  update Lucene version for 6.0-RC2 version
  Calculate and cache result when advanceExact is called (elastic#26920)
  Test query builder bwc against previous supported versions instead of just the current version.
  Set minimum_master_nodes on rolling-upgrade test (elastic#26911)
  Return List instead of an array from settings (elastic#26903)
  remove _primary and _replica shard preferences (elastic#26791)
  fixing typo in datehistogram-aggregation.asciidoc (elastic#26924)
  [API] Added the `terminate_after` parameter to the REST spec for "Count" API
  Setup debug logging for qa.full-cluster-restart
  Enable BWC testing against other remotes
  Use LF line endings in Painless generated files (elastic#26822)
  [DOCS] Added info about snapshotting your data before an upgrade.
  Add documentation about disabling `_field_names`. (elastic#26813)
  ...
jasontedor added a commit to jasontedor/elasticsearch that referenced this pull request Oct 10, 2017
* master:
  Fix handling of paths containing parentheses
  Allow only a fixed-size receive predictor (elastic#26165)
  Add Homebrew instructions to getting started
  ingest: Fix bug that prevent date_index_name processor from accepting timestamps specified as a json number
  Scripting: Fix expressions to temporarily support filter scripts (elastic#26824)
  Docs: Add note to contributing docs warning against tool based refactoring (elastic#26936)
  Fix thread context handling of headers overriding (elastic#26068)
  SearchWhileCreatingIndexIT: remove usage of _only_nodes
@hanbj hanbj deleted the threadcontext branch January 16, 2019 06:36
@jpountz jpountz added the :Distributed Coordination/Network Http and internode communication implementations label Jan 29, 2019
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-distributed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>bug :Distributed Coordination/Network Http and internode communication implementations v6.1.0 v7.0.0-beta1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants