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

Provide LocalMapStats data for invocations from Lite members [HZ-2072] #24871

Merged
merged 4 commits into from
Jun 26, 2023

Conversation

JamesHazelcast
Copy link
Contributor

@JamesHazelcast JamesHazelcast commented Jun 21, 2023

Context: Metrics for IMaps are stored in LocalMapStats objects, which are provided by LocalMapStatsProvider. Certain MapOperation metrics (get, set, put, & remove) are logged when MapProxySupport#invokeOperation is called, which uses MapOperationStatsUpdater.incrementOperationStats. This happens for operations not executed on the local member as well, which means that a Lite member invoking IMap#put will cause a PutOperation being executed on another (non-Lite) member, but it will increment stats on its own member.

Problem: Due to Lite members not owning any data themselves, they do not report any metrics for MapOperations. This means that metrics on these operations are lost with the current metric collection mechanics.

Original Solution: Tweaking LocalMapStatsProvider#addStatsOfNoDataIncludedMaps to include a isLiteMember check which, if passed, will include metrics from the provider's statsMap field (which is already correctly updated). This is only done if an empty LocalMapStats object would've been passed otherwise, and the statsMap entry contains non-zero statistics.

Revised Solution: Tweaking LocalMapStatsProvider#addStatsOfNoDataIncludedMaps to provide the local statsMap value of LocalMapStatsImpl when there is no data currently included - this LocalMapStatsImpl contains the invocation counts from Lite members (which is already correctly updated). This is only done if an empty LocalMapStats object would've been passed otherwise, and the statsMap value is not null.

While testing I also identified a scenario where a Lite member can have its own LocalMapStatsImpl for a map which it does not currently hold a MapContainer for - this means the stats object is not cleaned up. I made changes to MapServiceContextImpl#destroyMap to account for this and clean up these objects on Lite members.

I have also added a very simple regression test which ensures Lite members produce metrics after IMap#put is called.

Note: It may be worth reworking our map statistic capturing mechanic, shifting the responsibility to the executing member rather than the invoker. I chose my approach with the mindset of changing the least amount of existing functionality/behaviour, while also stopping these metrics being lost entirely as they currently are.

Closes https://hazelcast.atlassian.net/browse/HZ-2072

**Context:** Metrics for IMaps are stored in `LocalMapStats` objects, which
are provided by `LocalMapStatsProvider`. Certain MapOperation metrics
(get, set, put, & remove) are logged when `MapProxySupport#invokeOperation`
is called, which uses `MapOperationStatsUpdater.incrementOperationStats`.
This happens for operations not executed on the local member as well, which
means that a Lite member invoking `IMap#put` will cause a `PutOperation`
being executed on another (non-Lite) member, but it will increment stats
on its own member.

**Problem:** Due to Lite members not owning any data themselves, they do not report
any metrics for MapOperations. This means that metrics on these operations
are lost with the current metric collection mechanics.

**Solution:** Tweaking `LocalMapStatsProvider#addStatsOfNoDataIncludedMaps`
to include a `isLiteMember` check which, if passed, will include metrics
from the provider's `statsMap` field (which is already correctly updated).
This is only done if an empty `LocalMapStats` object would've been passed
otherwise, and the `statsMap` entry contains non-zero statistics.

I have also added a very simple regression test which ensures Lite members
produce metrics after `IMap#put` is called.

**Note:** It may be worth reworking our map statistic capturing mechanic,
shifting the responsibility to the executing member rather than the invoker.
I chose my approach with the mindset of changing the least amount of
existing functionality/behaviour, while also stopping these metrics being
lost entirely as they currently are.
@JamesHazelcast
Copy link
Contributor Author

Leaving as a draft request for now as I'm looking for feedback on this approach and whether there's any considerations I've missed.

@hz-devops-test
Copy link

The job Hazelcast-pr-builder of your PR failed. (Hazelcast internal details: build log, artifacts).
Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log file

Based on Ahmet's feedback from my PR - testing suggests that after a Lite
member invokes a `PutOperation`, it does get a `MapContainer` object,
meaning that cleanup of the `LocalMapStatsImpl` is already handled in the
existing `MapServiceContextImpl#destroyMap` function. I made an addition
to my regression test which tests for this and confirms this destruction.
Copy link
Member

@ahmetmircik ahmetmircik left a comment

Choose a reason for hiding this comment

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

comments

The `MapProxySupport#getLocalMapStats` method is creative, so if there
was no `LocalMapStatsImpl` created prior, it would be created - also
under the hood it calls back to the `LocalMapStatsProvider` to check
its `statsMap` field anyway, so we can cut out the middle man and
check the `statsMap` field directly. If no existing stats exist in the
`statsMap` map, then an empty `LocalMapStatsImpl` is used instead -
this maintains any prior functionality related to "empty stats".

My testing also discovered that our current `MapServiceContext#destroyMap`
method does not account for Lite members that never access a Map (which
means they never get a `MapContainer`), but do get a `LocalMapStatsImpl`
created when their map proxy is created. As they have no `MapContainer`,
the `MapServiceContext#destroyMap` method does not reach the calls where
the stats are cleaned up - this commit resolves that by calling the
removal function even if there is no `MapContainer` present.
@JamesHazelcast JamesHazelcast marked this pull request as ready for review June 23, 2023 09:26
@JamesHazelcast JamesHazelcast merged commit cb368d4 into hazelcast:master Jun 26, 2023
8 checks passed
@hz-devops-test
Copy link

The job Hazelcast-pr-builder of your PR failed. (Hazelcast internal details: build log, artifacts).
Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log file

@JamesHazelcast JamesHazelcast deleted the fix/5.4/hz-2072 branch September 21, 2023 13:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants