Skip to content

Memoize Connection#rootless? correctly - #608

Merged
ls-todd-lunter merged 2 commits into
upserve:masterfrom
tas50:fix-rootless-memoization
Oct 24, 2026
Merged

ls-todd-lunter merged 2 commits into
upserve:masterfrom
tas50:fix-rootless-memoization

Conversation

@tas50

@tas50 tas50 commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

@rootless ||= (info["Rootless"] == true) cannot cache a false result — ||= re-evaluates whenever the memo is false or nil. #info is not memoized either, so every call against a non-rootless daemon issued a fresh /info request.

Measured against a real daemon before the fix:

5x Docker.rootless? -> 5 /info requests

After:

5x Docker.rootless? -> 1 /info request

The fix

Test for the ivar with defined? rather than relying on truthiness.

Also

Adds a guard spec for #podman?. It uses the same ||= idiom, but is backed by the memoized #version, so it already makes only one /version request. The spec pins that so it cannot regress into the same trap. No behaviour change there.

Verification

The new only queries /info once spec was confirmed to fail before the change:

expected: 1 time with arguments: ("/info")
received: 2 times with arguments: ("/info")

connection_spec goes from 13 examples to 17, with no new failures.

Note on CI

The one failing example on this branch (its(:resource)) is pre-existing on master — I confirmed master alone reports 13 examples, 1 failure for the same spec. It is fixed by #605, and CI here will stay red until that lands.

tas50 and others added 2 commits August 23, 2026 12:40
`@rootless ||= (info['Rootless'] == true)` cannot cache a false result, and
#info is not memoized, so every call against a non-rootless daemon issued a
fresh /info request:

    5x Docker.rootless? -> 5 /info requests

Test for the ivar with defined? instead. Every daemon that is not rootless is
now one request rather than one per call:

    5x Docker.rootless? -> 1 /info request

Also adds a guard for #podman?, which uses the same `||=` idiom but is already
backed by the memoized #version, so it makes a single /version request. The spec
pins that behaviour so it does not regress into the same trap.
@ls-todd-lunter
ls-todd-lunter merged commit 5259d08 into upserve:master Oct 24, 2026
32 checks passed
ls-todd-lunter added a commit that referenced this pull request Oct 27, 2026
* Declare base64 as a runtime dependency so the gem loads on Ruby 3.4+ (#605)
* Replace multi_json with the json standard library and drop the multi_json dependency (#613)
* Keep the build context inside the build directory: symlinks are archived as symlinks rather than followed, and .dockerignore patterns can no longer reach outside the directory (#611)
* Send platform as a query parameter on Container.create (#607)
* Honor stdout: false and stderr: false in Container#exec (#609)
* Request an HTTP upgrade when attaching to stdin so the attach no longer hangs (#610)
* Memoize Connection#rootless? when the daemon is not rootless (#608)
* Add gemspec metadata (source_code_uri, bug_tracker_uri, rubygems_mfa_required) and build the gem file list without git (#615)
* Fix and update README examples and streaming read_timeout docs (#606, #585, #592)
* Fix CI, test through Ruby 4.0 and Docker 28 and 29, and remove Travis, Code Climate and unmaintained test image leftovers (#604, #605, #614, #616)
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