diff --git a/docs/changelog/133004.yaml b/docs/changelog/133004.yaml new file mode 100644 index 0000000000000..da87ab0803e55 --- /dev/null +++ b/docs/changelog/133004.yaml @@ -0,0 +1,5 @@ +pr: 133004 +summary: Limit frequency of feature last-used time updates +area: License +type: bug +issues: [] diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java index 3c7b089b4cd63..6b9b8266ae8b9 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java @@ -447,7 +447,13 @@ public String statusDescription() { void featureUsed(LicensedFeature feature) { checkExpiry(); - usage.put(new FeatureUsage(feature, null), epochMillisProvider.getAsLong()); + final long now = epochMillisProvider.getAsLong(); + final FeatureUsage feat = new FeatureUsage(feature, null); + final Long mostRecent = usage.get(feat); + // only update if needed, to prevent ConcurrentHashMap lock-contention on writes + if (mostRecent == null || now > mostRecent) { + usage.put(feat, now); + } } void enableUsageTracking(LicensedFeature feature, String contextName) { diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/XPackLicenseStateTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/XPackLicenseStateTests.java index d788a0b5abd37..710db0287fa2b 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/XPackLicenseStateTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/XPackLicenseStateTests.java @@ -244,6 +244,13 @@ public void testLastUsedMomentaryFeature() { lastUsed = licenseState.getLastUsed(); assertThat("feature.check updates usage", lastUsed.keySet(), containsInAnyOrder(usage)); assertThat(lastUsed.get(usage), equalTo(200L)); + + // updates to the last used timestamp only happen if the time has increased + currentTime.set(199); + goldFeature.check(licenseState); + lastUsed = licenseState.getLastUsed(); + assertThat("feature.check updates usage", lastUsed.keySet(), containsInAnyOrder(usage)); + assertThat(lastUsed.get(usage), equalTo(200L)); } public void testLastUsedMomentaryFeatureWithSameNameDifferentFamily() {