Add flag to MetadataDiff to make noop diffs cheaper#90101
Add flag to MetadataDiff to make noop diffs cheaper#90101original-brownbear merged 3 commits intoelastic:mainfrom original-brownbear:skip-noop-metadata-diff
Conversation
No need to rebuild a new metadata or send needless bytes if we know `before == after`. This should save quite a bit of work on data nodes during non-metadata state updates.
|
Pinging @elastic/es-distributed (Team:Distributed) |
| return; | ||
| } | ||
| } else { | ||
| noop = false; |
There was a problem hiding this comment.
Nit: noop is already assigned by this point, no need for the else branch
| indices = DiffableUtils.emptyDiff(); | ||
| templates = DiffableUtils.emptyDiff(); | ||
| customs = DiffableUtils.emptyDiff(); | ||
| reservedStateMetadata = DiffableUtils.emptyDiff(); |
There was a problem hiding this comment.
I wonder if it is possible or worth replacing constructor with a static factory? This way we could have a constant static empty diff
There was a problem hiding this comment.
Good point, we don't need a specific instance when reading. We even have a static factory already. I made use of that and reused the existing empty instance in SimpleDiffable now + made the constructor private to avoid abuse.
server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java
Outdated
Show resolved
Hide resolved
| private final Diff<Map<String, ReservedStateMetadata>> reservedStateMetadata; | ||
|
|
||
| // true if this diff is a noop because before and after were the same instance | ||
| private final boolean noop; |
There was a problem hiding this comment.
I think it is better to name this empty in a context of a diff
| @Override | ||
| public Metadata apply(Metadata part) { | ||
| if (noop) { | ||
| return part; |
| new DiffableUtils.DiffableValueReader<>(ReservedStateMetadata::readFrom, ReservedStateMetadata::readDiffFrom); | ||
|
|
||
| MetadataDiff(StreamInput in) throws IOException { | ||
| if (in.getVersion().onOrAfter(NOOP_METADATA_DIFF_VERSION)) { |
There was a problem hiding this comment.
Do we have a unit tests that checks serialization/deserialization of the MetadataDiff? DO we need one for an empty case?
There was a problem hiding this comment.
Turns out we don't, it's massively covered by existing tests but it's nice to have a test that makes sure we get instance equality for the empty diff to lock down this optimization. I added one now.
|
Thanks Ievgen, all points addressed now I think. |
|
Thanks Ievgen! |
The cluster coordination consistency layer relies on a couple of fields within `Metadata` which record the last _committed_ values on each node. In contrast, the rest of the cluster state can only be changed at _accept_ time. In the past we would copy these fields over from the master on every publication, but since elastic#90101 we don't copy anything at all if the `Metadata` is unchanged on the master. However, the master computes the diff against the last _committed_ state whereas the receiving nodes apply the diff to the last _accepted_ state, and this means if the master sends a no-op `Metadata` diff then the receiving node will revert its last-committed values to the ones included in the state it last accepted. With this commit we adjust `CoordinationState` to ignore changes to the last-committed fields at accept time.
The cluster coordination consistency layer relies on a couple of fields within `Metadata` which record the last _committed_ values on each node. In contrast, the rest of the cluster state can only be changed at _accept_ time. In the past we would copy these fields over from the master on every publication, but since elastic#90101 we don't copy anything at all if the `Metadata` is unchanged on the master. However, the master computes the diff against the last _committed_ state whereas the receiving nodes apply the diff to the last _accepted_ state, and this means if the master sends a no-op `Metadata` diff then the receiving node will revert its last-committed values to the ones included in the state it last accepted. With this commit we include the last-committed values alongside the cluster state diff so that they are always copied properly.
The cluster coordination consistency layer relies on a couple of fields within `Metadata` which record the last _committed_ values on each node. In contrast, the rest of the cluster state can only be changed at _accept_ time. In the past we would copy these fields over from the master on every publication, but since elastic#90101 we don't copy anything at all if the `Metadata` is unchanged on the master. However, the master computes the diff against the last _committed_ state whereas the receiving nodes apply the diff to the last _accepted_ state, and this means if the master sends a no-op `Metadata` diff then the receiving node will revert its last-committed values to the ones included in the state it last accepted. With this commit we include the last-committed values alongside the cluster state diff so that they are always copied properly.
The cluster coordination consistency layer relies on a couple of fields within `Metadata` which record the last _committed_ values on each node. In contrast, the rest of the cluster state can only be changed at _accept_ time. In the past we would copy these fields over from the master on every publication, but since #90101 we don't copy anything at all if the `Metadata` is unchanged on the master. However, the master computes the diff against the last _committed_ state whereas the receiving nodes apply the diff to the last _accepted_ state, and this means if the master sends a no-op `Metadata` diff then the receiving node will revert its last-committed values to the ones included in the state it last accepted. With this commit we include the last-committed values alongside the cluster state diff so that they are always copied properly. Closes #90158
The cluster coordination consistency layer relies on a couple of fields within `Metadata` which record the last _committed_ values on each node. In contrast, the rest of the cluster state can only be changed at _accept_ time. In the past we would copy these fields over from the master on every publication, but since elastic#90101 we don't copy anything at all if the `Metadata` is unchanged on the master. However, the master computes the diff against the last _committed_ state whereas the receiving nodes apply the diff to the last _accepted_ state, and this means if the master sends a no-op `Metadata` diff then the receiving node will revert its last-committed values to the ones included in the state it last accepted. With this commit we include the last-committed values alongside the cluster state diff so that they are always copied properly. Closes elastic#90158 Backport of elastic#92259 to 8.6
The cluster coordination consistency layer relies on a couple of fields within `Metadata` which record the last _committed_ values on each node. In contrast, the rest of the cluster state can only be changed at _accept_ time. In the past we would copy these fields over from the master on every publication, but since #90101 we don't copy anything at all if the `Metadata` is unchanged on the master. However, the master computes the diff against the last _committed_ state whereas the receiving nodes apply the diff to the last _accepted_ state, and this means if the master sends a no-op `Metadata` diff then the receiving node will revert its last-committed values to the ones included in the state it last accepted. With this commit we include the last-committed values alongside the cluster state diff so that they are always copied properly. Closes #90158 Backport of #92259 to 8.6
No need to rebuild a new metadata or send needless bytes if we know
before == after. This should save quite a bit of work on data nodes during non-metadata state updates.relates #77466