Thanks to visit codestin.com
Credit goes to Github.com

Skip to content

Conversation

@ankit98040
Copy link

@ankit98040 ankit98040 commented Dec 22, 2025

What type of PR is this?

/kind cleanup

What this PR does / why we need it:

This PR optimizes the Size() method in internal/memorystore from O(N) to O(1) complexity by maintaining an atomic counter instead of iterating over the entire sync.Map on every call.

Problem: The previous implementation iterated over all entries in the map to count them, which becomes inefficient as the number of containers/sandboxes grows.

Solution:

  • Added an atomic.Int64 counter to track the number of elements in the store
  • Updated Add() to use Swap() and increment the counter only for new keys
  • Updated Delete() to use LoadAndDelete() and decrement the counter only when a key is actually removed
  • Changed Size() to simply return the atomic counter value

This improves performance for operations that frequently check the store size, especially in environments with many containers.

Which issue(s) this PR fixes:

None

Special notes for your reviewer:

The changes are thread-safe as they use atomic operations and the existing sync.Map guarantees. The logic ensures:

  • Updating an existing key (via Add) does not increment the counter
  • Deleting a non-existent key does not decrement the counter
  • All operations remain concurrent-safe

I verified the correctness with a standalone test that validates Add, Update, and Delete operations maintain accurate counts.

Does this PR introduce a user-facing change?

None

Summary by CodeRabbit

  • Refactor
    • Removed an internal store-size query from the public interface; internal storage behavior otherwise unchanged.
  • Tests
    • Updated unit tests to stop relying on the removed size query and to assert expected list results directly.

✏️ Tip: You can customize this high-level summary in your review settings.

@ankit98040 ankit98040 requested a review from mrunalp as a code owner December 22, 2025 11:14
@openshift-ci openshift-ci bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. dco-signoff: yes Indicates the PR's author has DCO signed all their commits. labels Dec 22, 2025
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Dec 22, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: ankit98040
Once this PR has been reviewed and has the lgtm label, please assign haircommander for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot requested review from hasan4791 and klihub December 22, 2025 11:14
@openshift-ci openshift-ci bot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Dec 22, 2025
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Dec 22, 2025

Hi @ankit98040. Thanks for your PR.

I'm waiting for a github.com member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@coderabbitai
Copy link

coderabbitai bot commented Dec 22, 2025

Walkthrough

Removed the Size() method from the Storer[T] interface and its memoryStore implementation; tests updated to stop depending on Size() when asserting list length. No other behavioral changes to store operations reported.

Changes

Cohort / File(s) Summary
Memory store API removal
internal/memorystore/memory_store.go
Removed the Size() int method from the Storer[T] interface and deleted the func (c *memoryStore[T]) Size() (l int) implementation. No other store methods were modified.
Tests adjusted to remove Size dependency
internal/memorystore/memory_store_test.go
Updated tests to eliminate assertions that used the store's Size(); e.g., List test now asserts non-nil and specific length without referencing Size().

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Confirm removal of Size() doesn't break consumers outside this diff (search for usages).
  • Verify interface changes compile across packages that import Storer[T].
  • Review tests ensuring they still validate intended behavior without Size().

Poem

I hopped through maps with careful paws,
The size call gone — I pause, then applause.
Lists still leap, keys come and go,
A quieter API, steady and slow. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The PR title accurately describes the main change: removal of the Size() method from the memorystore interface and implementation.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
internal/memorystore/memory_store.go (2)

46-48: Optional: Consider explicit counter initialization for clarity.

The count field relies on Go's zero-value initialization (0 for atomic.Int64), which is correct for an empty store. While this works perfectly, you could make the intent more explicit:

 func New[T AnyCreated[T]]() Storer[T] {
-	return &memoryStore[T]{s: sync.Map{}}
+	return &memoryStore[T]{
+		s:     sync.Map{},
+		count: atomic.Int64{},
+	}
 }

This has no functional benefit but may improve readability.


40-43: Add a comment explaining the counter's purpose.

As per coding guidelines, add comments explaining 'why' not 'what'. The count field should be documented to explain its purpose as a performance optimization.

📝 Suggested documentation
 type memoryStore[T AnyCreated[T]] struct {
 	s     sync.Map
+	// count maintains the number of elements in the store for O(1) Size() queries.
+	// It's updated atomically during Add() and Delete() operations.
 	count atomic.Int64
 }

Based on coding guidelines: "Add comments explaining 'why' not 'what' in Go code".

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44f68df and 8c4aed8.

📒 Files selected for processing (1)
  • internal/memorystore/memory_store.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Use interface-based design and dependency injection patterns in Go code
Propagate context.Context through function calls in Go code
Use fmt.Errorf with %w for error wrapping in Go code
Use logrus with structured fields for logging in Go code
Add comments explaining 'why' not 'what' in Go code
Use platform-specific file naming: *_{linux,freebsd}.go for platform-dependent code

Files:

  • internal/memorystore/memory_store.go
🧠 Learnings (2)
📚 Learning: 2025-12-17T13:38:34.646Z
Learnt from: bitoku
Repo: cri-o/cri-o PR: 9667
File: server/container_create.go:1233-1236
Timestamp: 2025-12-17T13:38:34.646Z
Learning: In the cri-o/cri-o repository, protobuf-generated Get* methods for k8s.io/cri-api types are nil-safe: if the receiver is nil, GetX() returns the zero value instead of panicking. Do not add explicit nil checks before chaining calls on such getters. Apply this guidance to all Go code that uses these generated getters across the codebase.

Applied to files:

  • internal/memorystore/memory_store.go
📚 Learning: 2025-12-18T13:28:24.244Z
Learnt from: bitoku
Repo: cri-o/cri-o PR: 9676
File: internal/lib/stats/cgroup_stats_unsupported.go:1-7
Timestamp: 2025-12-18T13:28:24.244Z
Learning: In the cri-o/cri-o repository, for platform-specific types guarded by Go build tags (for example //go:build !linux), implement empty structs for unsupported platforms to permit compilation and clearly indicate the feature is not available rather than mirroring the Linux struct with unpopulated fields. Apply this pattern to all relevant platform-specific files across the codebase (i.e., any file under build-taged sections that should compile on all targets but lacks full implementation for some platforms).

Applied to files:

  • internal/memorystore/memory_store.go
🔇 Additional comments (5)
internal/memorystore/memory_store.go (5)

5-5: LGTM: Import addition is appropriate.

The sync/atomic import is required for the atomic.Int64 counter operations.


53-55: LGTM: Add() logic correctly handles inserts vs. updates.

Using Swap() with the loaded return value ensures the counter is incremented only when a new key is inserted, not when updating an existing key. This maintains an accurate count.


72-74: LGTM: Delete() logic correctly handles actual removals.

Using LoadAndDelete() with the loaded return value ensures the counter is decremented only when a key is actually removed, not when attempting to delete a non-existent key. This maintains an accurate count.


87-88: LGTM: Size() now runs in O(1) time.

The atomic counter approach successfully eliminates the need to iterate over the map, achieving the performance goal stated in the PR objectives.


41-42: Eventual consistency between map and counter is a real concern; verify if acceptable for use case.

The code has a consistency window: c.s.Swap()/c.s.LoadAndDelete() and c.count.Add() are separate operations on different objects. A concurrent Size() call can observe a count that lags behind the actual map state. Assess whether callers tolerate this eventual consistency or if operations must be coordinated under a shared lock.

@bitoku
Copy link
Contributor

bitoku commented Dec 22, 2025

Thank you for the PR @ankit98040 !

In fact, Size() is only used in this test here. (correct me if I'm wrong)

t.Describe("List", func() {
It("should succeed", func() {
// Given
const sandboxID = "id"
sut.Add(sandboxID, testSandbox)
Expect(sut.Get(sandboxID)).NotTo(BeNil())
// When
sandboxes := sut.List()
// Then
Expect(sandboxes).NotTo(BeNil())
Expect(sandboxes).To(HaveLen(sut.Size()))
Expect(len(sandboxes)).To(BeEquivalentTo(1))
})
})

So this optimization should degrade the performance unfortunately because of unnecessary size management though It should be negligible.
I'd rather remove Size() instead, from the test too, not to use this inefficient Size() by mistake. wdyt?

The Size() method was only used in one test and added unnecessary
overhead. This commit removes it entirely:

- Removed Size() from Storer interface
- Removed Size() implementation from memoryStore
- Updated test to remove redundant Size() assertion

This eliminates the O(N) iteration cost and prevents future misuse
of this inefficient method.

Signed-off-by: Ankit Pramanik <[email protected]>
@ankit98040 ankit98040 force-pushed the perf/memorystore-size-optimization branch from 8c4aed8 to fa5afc5 Compare December 22, 2025 13:52
@bitoku
Copy link
Contributor

bitoku commented Dec 22, 2025

/ok-to-test

@openshift-ci openshift-ci bot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Dec 22, 2025
@bitoku bitoku changed the title perf(memorystore): optimize Size() to O(1) Remove unused memorystore.Size() Dec 22, 2025
@openshift-ci openshift-ci bot added release-note-none Denotes a PR that doesn't merit a release note. and removed release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Dec 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Indicates the PR's author has DCO signed all their commits. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. release-note-none Denotes a PR that doesn't merit a release note.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants