Skip to content

perf: skip ImmutableMetadata allocation when builder has no entries#1971

Merged
toddbaert merged 1 commit into
open-feature:mainfrom
tobias-ibounig-dt:perf/pr-8-immutablemetadata
Jun 19, 2026
Merged

perf: skip ImmutableMetadata allocation when builder has no entries#1971
toddbaert merged 1 commit into
open-feature:mainfrom
tobias-ibounig-dt:perf/pr-8-immutablemetadata

Conversation

@tobias-ibounig-dt

@tobias-ibounig-dt tobias-ibounig-dt commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

This PR

  • ImmutableMetadata.build() returns EMPTY singleton when the builder's metadata map is empty
  • ImmutableMetadata.asUnmodifiableMap() returns Collections.emptyMap() singleton when metadata is empty

Related Issues

None

Notes

ImmutableMetadata.builder().build() is the @Builder.Default for ProviderEvaluation.flagMetadata, so every flag evaluation without explicit metadata allocated a throwaway ImmutableMetadata backed by an empty HashMap. Returning EMPTY is safe — ImmutableMetadata has no mutation methods.

asUnmodifiableMap() now returns the JDK Collections.emptyMap() singleton for empty metadata, avoiding the UnmodifiableMap wrapper allocation.

Metric Baseline This PR Delta
run:+totalAllocatedInstances 2,239,379 2,145,282 −94,097 (−4.2%)
run:+totalAllocatedBytes 106,304,128 102,105,728 −4,198,400 (−3.9%)

Follow-up Tasks

  • More PRs with memory improvements
  • Update benchmark.txt after all are applied

Summary by CodeRabbit

  • Bug Fixes

    • Optimized empty metadata handling to improve performance and ensure consistent behavior across metadata operations.
  • Tests

    • Enhanced test coverage for empty metadata scenarios, including validation of immutability guarantees.

Signed-off-by: Tobias Ibounig <tobias.ibounig@dynatrace.com>
@tobias-ibounig-dt tobias-ibounig-dt requested review from a team as code owners June 19, 2026 11:39
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b74093e-23bb-4991-978e-ef8eeec1ea7a

📥 Commits

Reviewing files that changed from the base of the PR and between cc837b1 and d8d3088.

📒 Files selected for processing (2)
  • src/main/java/dev/openfeature/sdk/ImmutableMetadata.java
  • src/test/java/dev/openfeature/sdk/ImmutableMetadataTest.java

📝 Walkthrough

Walkthrough

ImmutableMetadata.asUnmodifiableMap() now returns Collections.emptyMap() for empty metadata, and ImmutableMetadataBuilder.build() short-circuits to the ImmutableMetadata.EMPTY singleton when the builder holds no entries. Two new tests verify singleton identity and that the empty map rejects mutation.

Changes

ImmutableMetadata empty-singleton optimization

Layer / File(s) Summary
Empty singleton short-circuit
src/main/java/dev/openfeature/sdk/ImmutableMetadata.java
build() returns the EMPTY singleton when the builder's metadata is empty; asUnmodifiableMap() returns Collections.emptyMap() instead of an unmodifiable view of an empty map.
Empty metadata test coverage
src/test/java/dev/openfeature/sdk/ImmutableMetadataTest.java
Imports updated to use AssertJ and @DisplayName; new tests assert the empty builder returns the EMPTY singleton and that asUnmodifiableMap() on EMPTY yields an empty unmodifiable map that throws on put.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main optimization: skipping ImmutableMetadata allocation when the builder is empty, which is the core performance improvement.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Jun 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.11%. Comparing base (cc837b1) to head (d8d3088).

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #1971      +/-   ##
============================================
+ Coverage     92.11%   93.11%   +0.99%     
- Complexity      660      664       +4     
============================================
  Files            59       59              
  Lines          1624     1626       +2     
  Branches        182      183       +1     
============================================
+ Hits           1496     1514      +18     
+ Misses           80       66      -14     
+ Partials         48       46       -2     
Flag Coverage Δ
unittests 93.11% <100.00%> (+0.99%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@toddbaert toddbaert merged commit e014572 into open-feature:main Jun 19, 2026
12 checks passed
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants