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
Added wait_for_metadata_version parameter to cluster state api. #35535
Added wait_for_metadata_version parameter to cluster state api. #35535
Conversation
The `wait_for_metadata_version` parameter will instruct the cluster state api to return a cluster state until the metadata's version is equal or greater than the version specified in `wait_for_metadata_version` or wait until till the specified `wait_for_timeout` has expired. In the case metadata's version is equal or higher than `wait_for_metadata_version` then the api will immediately return. This feature is useful to avoid external components from constantly polling the cluster state to whether somethings have changed in the cluster state's metadata.
Pinging @elastic/es-core-infra |
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.
The change looks good overall. I left a few minor comments.
The only thing I am doubting is whether or not to return the last known state after a timeout. If we don't do that, we don't need to change the ClusterStateObserver.Listener
interface. What is your thinking behind sending back a cluster state in this case as opposed to an empty response that would more clearly indicate the request timed out?
I'll do another quick pass after we come to a decision on this point.
* Returns whether waiting for a cluster state wait a metadata version equal or higher than the specified | ||
* metadata version timed out. | ||
*/ | ||
public boolean isTimedOut() { |
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.
The Javadocs are clear but I think the name could be clearer and reflect the name of the parameter on the request: isWaitForTimedOut
|
||
public ClusterStateResponse() { | ||
} | ||
|
||
public ClusterStateResponse(ClusterName clusterName, ClusterState clusterState, long sizeInBytes) { | ||
public ClusterStateResponse(ClusterName clusterName, ClusterState clusterState, long sizeInBytes, boolean timedOut) { |
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.
timedOut
-> waitForTimedOut
(to clarify that it's not a generic timeout)
@@ -40,14 +41,16 @@ | |||
// the total compressed size of the full cluster state, not just | |||
// the parts included in this response | |||
private ByteSizeValue totalCompressedSize; | |||
private boolean timedOut = false; |
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.
timedOut
-> waitForTimedOut
|
||
@Override | ||
public int hashCode() { | ||
// Best effort for testing. Left out cluster state, because it doesn't implement equals() and hashcode() |
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.
Maybe hash the version and the master node ID (that's what an observer considers to be the same for purposes of comparing cluster states)?
ClusterStateResponse response = (ClusterStateResponse) o; | ||
return timedOut == response.timedOut && | ||
Objects.equals(clusterName, response.clusterName) && | ||
// Best effort. Left out cluster state, because it doesn't implement equals() and hashcode() |
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.
Maybe compare the version and the master node ID (that's what an observer considers to the same for purposes of comparing cluster states)?
|
||
private void buildResponse(final ClusterStateRequest request, | ||
final ClusterState currentState, | ||
final boolean timedOut, |
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.
waitForTimedOut
Thanks for reviewing @jasontedor
I wanted it to be similar to the shard changes api. In this case when it times out waiting for new ops, it returns a response with potential updated mapping / settings version and no ops. In the case of cluster state api, other things outside metadata may have changed and so it made sense to me to return the cluster state with a timed out flag. |
…e in the response and set timed out field to true.
After talking to @jasontedor, it made sense to not return a cluster state when wait for metadata version has timed out, so I made that change. This also means the change to |
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.
Looking good. I left a few more minors.
} | ||
|
||
@Override | ||
public void writeTo(StreamOutput out) throws IOException { | ||
super.writeTo(out); | ||
clusterName.writeTo(out); | ||
if (out.getVersion().onOrAfter(Version.V_6_3_0)) { | ||
clusterState.writeTo(out); | ||
if (out.getVersion().onOrAfter(Version.V_7_0_0)) { |
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.
TODO: 6.6.0
@Override | ||
public void readFrom(StreamInput in) throws IOException { | ||
super.readFrom(in); | ||
clusterName = new ClusterName(in); | ||
clusterState = ClusterState.readFrom(in, null); | ||
if (in.getVersion().onOrAfter(Version.V_7_0_0)) { |
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.
TODO: 6.6.0
@@ -56,6 +67,10 @@ public void testSerialization() throws Exception { | |||
assertThat(deserializedCSRequest.blocks(), equalTo(clusterStateRequest.blocks())); | |||
assertThat(deserializedCSRequest.indices(), equalTo(clusterStateRequest.indices())); | |||
assertOptionsMatch(deserializedCSRequest.indicesOptions(), clusterStateRequest.indicesOptions()); | |||
if (testVersion.onOrAfter(Version.V_7_0_0)) { |
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.
TODO: 6.6.0
} | ||
|
||
public ClusterStateRequest waitForMetaDataVersion(long expectedMetaDataVersion) { | ||
this.waitForMetaDataVersion = expectedMetaDataVersion; |
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.
Should we require this be >= 1?
@@ -94,6 +98,7 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC | |||
@Override | |||
public RestResponse buildResponse(ClusterStateResponse response, XContentBuilder builder) throws Exception { | |||
builder.startObject(); | |||
builder.field(Fields.TIMED_OUT, response.isWaitForTimedOut()); |
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.
I wonder if this field should be called wait_for_timed_out
? And I wonder if we should only include it if wait_for_metadata_version
was set on the request?
@jasontedor I've updated the PR. |
|
||
public ClusterStateRequest waitForMetaDataVersion(long waitForMetaDataVersion) { | ||
if (waitForMetaDataVersion < 1) { | ||
throw new IllegalArgumentException("waitForMetaDataVersion should be >= 1"); |
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.
Include the invalid value?
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.
@martijnvg What do you think about including the default value here?
}, | ||
"wait_for_timeout" : { | ||
"type": "time", | ||
"description": "The maximum time to wait for wait_for_metadata_version before stop waiting and then the last observed cluster state is returned" |
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.
This documentation comment is stale now.
@@ -75,11 +79,24 @@ public ByteSizeValue getTotalCompressedSize() { | |||
return totalCompressedSize; | |||
} | |||
|
|||
/** | |||
* Returns whether waiting for a cluster state wait a metadata version equal or higher than the specified |
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.
Returns whether -> Returns whether the request timed out waiting... and remove timed out from the end of the sentence.
assertThat(future2.isDone(), is(true)); | ||
}); | ||
ClusterStateResponse response = future2.actionGet(); | ||
assertThat(response.isWaitForTimedOut(), is(false)); |
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.
On a really slow or overloaded machine, this can timeout in a second and cause spurious build failures. How about setting the timeout really high here (e.g., one hour). Then, in the test when you test that the timeout works, set the timeout low again.
I left a few comments, no need for another round. |
…tic#35535) The `wait_for_metadata_version` parameter will instruct the cluster state api to only return a cluster state until the metadata's version is equal or greater than the version specified in `wait_for_metadata_version`. If the specified `wait_for_timeout` has expired then a timed out response is returned. (a response with no cluster state and wait for timed out flag set to true) In the case metadata's version is equal or higher than `wait_for_metadata_version` then the api will immediately return. This feature is useful to avoid external components from constantly polling the cluster state to whether somethings have changed in the cluster state's metadata.
The `wait_for_metadata_version` parameter will instruct the cluster state api to only return a cluster state until the metadata's version is equal or greater than the version specified in `wait_for_metadata_version`. If the specified `wait_for_timeout` has expired then a timed out response is returned. (a response with no cluster state and wait for timed out flag set to true) In the case metadata's version is equal or higher than `wait_for_metadata_version` then the api will immediately return. This feature is useful to avoid external components from constantly polling the cluster state to whether somethings have changed in the cluster state's metadata.
The
wait_for_metadata_version
parameter will instruct the cluster stateapi to return a cluster state until the metadata's version is equal or
greater than the version specified in
wait_for_metadata_version
or waituntil till the specified
wait_for_timeout
has expired, in this case thecluster state is returned and
time_out
field is set to true.In the case metadata's version is equal or higher than
wait_for_metadata_version
then this api will immediately return.
This feature is useful to avoid external components from constantly
polling the cluster state to whether somethings have changed in the
cluster state's metadata.
I'm not sure what the best feature label for this issue is, so I labelled it as
:Core/Core
. I'm happy to change the label.