Skip to content

Narrow distribution task locks for unchanged base_path#7896

Open
pablomh wants to merge 1 commit into
pulp:mainfrom
pablomh:distribution-lock-narrowing-pr
Open

Narrow distribution task locks for unchanged base_path#7896
pablomh wants to merge 1 commit into
pulp:mainfrom
pablomh:distribution-lock-narrowing-pr

Conversation

@pablomh

@pablomh pablomh commented Jul 23, 2026

Copy link
Copy Markdown

Problem

Async distribution CUD operations currently reserve the domain-wide
pdrn:<domain>:distributions resource unconditionally. For ordinary
updates that leave base_path unchanged, this serializes unrelated
pulpcore.app.tasks.base.ageneral_update tasks behind a single lock.

This showed up as a bottleneck during capsule sync, where many
RefreshDistribution updates can run at once but end up waiting on the
same domain-wide reservation.

What this changes

This patch narrows distribution task reservations when the effective
base_path does not change:

  • create: keep the domain-wide distributions lock
  • delete: keep the domain-wide distributions lock
  • update with changed base_path: keep the broader lock
  • update with unchanged base_path: reserve only the distribution instance

The implementation also handles partial PATCH requests correctly by
falling back to instance.base_path when base_path is omitted from the
request body.

Test coverage

Adds a functional test covering the reservation behavior for:

  • create
  • partial update with no base_path in the payload
  • partial update with unchanged base_path
  • partial update with changed base_path
  • delete

Performance notes

Tested with Satellite 6.20 Stream,
~175 capsules, 15 Pulp workers).

For completed pulpcore.app.tasks.base.ageneral_update tasks, lock usage
shifted from all domain-wide reservations to a mix of domain and
instance-scoped reservations:

Lock type Before patch After patch
Domain-wide 110 26
Instance-only 0 42

Block wait times improved substantially:

Metric Before (domain-locked) After domain-locked After instance-locked
P95 6.98s 75ms 28ms
P99 10.12s 105ms 29ms
Max 10.16s 121ms 29ms

These results are consistent with removing unnecessary serialization for
ordinary distribution updates while preserving the broader lock when the
base_path namespace can change.

@gerrod3

gerrod3 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Can you add a changelog for this issue? #3322

@pablomh
pablomh force-pushed the distribution-lock-narrowing-pr branch from c74e46f to 6faf576 Compare July 23, 2026 18:04
@pablomh

pablomh commented Jul 23, 2026

Copy link
Copy Markdown
Author

Done :)

@gerrod3

gerrod3 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Not sure what is up with lint, maybe try rebasing with main. Also can you add fixes: #3322 to your commit message? Finally if you want this backported to older pulpcores mark the changelog as a bugfix.

@pablomh
pablomh force-pushed the distribution-lock-narrowing-pr branch from 6faf576 to cb2a1be Compare July 23, 2026 21:22
@pablomh

pablomh commented Jul 23, 2026

Copy link
Copy Markdown
Author

I'd like it to be backported to at least the release(s) that are part of Satellite 6.19.z.

@pablomh
pablomh force-pushed the distribution-lock-narrowing-pr branch 2 times, most recently from a15c525 to 951ea58 Compare July 23, 2026 21:32
…path

Only reserve the domain-wide distributions resource for operations that can affect base_path overlap validation. Distribution creates, deletes, and updates that change base_path continue to reserve `pdrn:<domain>:distributions`, while updates that leave base_path unchanged now reserve only the distribution instance itself.

This reduces unnecessary serialization of `ageneral_update` tasks for ordinary distribution updates, including partial PATCH requests that omit base_path or send the existing base_path unchanged.

Add a functional test covering the reserved resources used for create, partial update without base_path, partial update with unchanged base_path, partial update with changed base_path, and delete.

Co-authored-by: Cursor <cursoragent@cursor.com>

@mdellweg mdellweg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am a tiny bit concerned about Zero Downtime Upgrades here.
An old task (dispatched before this change) updating a distribution would only lock on the domain:distributions and a new one only on the single distribution.
Since distributions themselves are rather shallow, I cannot think about a situation where this collision leads to real world impacts. But my lack of imagination here is no guarantee for correctness.

"""
Reserve the narrowest safe lock for async distribution operations.

Creates, deletes, and base_path changes still lock the domain-wide distributions resource

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe add a statement that "base_path overlap validation" is the main concern why this function even exists.

I'm wondering if we can safely assume that deleting a distribution will never violate base_path overlaps?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, that is the main reason this logic exists, and I can make that clearer in the docstring.

I would still keep deletes on the broader lock. A delete does not create an overlap by itself, but it does release a base_path, so it is still part of the same domain-wide consistency concern as creates and moves.

return [instance, domain_distributions]

request_data = getattr(getattr(self, "request", None), "data", {})
requested_base_path = request_data.get("base_path", instance.base_path)

@mdellweg mdellweg Jul 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How come this is not None for a patch call that does not contain "base-path".

The test suggests, it actually works though (assuming it would actually pass once the linting works again).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

For a PATCH that does not include base_path, we treat that as base_path staying unchanged, so it stays on the instance-only lock.

The test is meant to cover exactly that case. If it helps, I can rewrite that branch to make the “field omitted means unchanged” behavior more explicit.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh you feed the current value as default. Never mind. Ignore me on this.

@pablomh

pablomh commented Jul 24, 2026

Copy link
Copy Markdown
Author

I am a tiny bit concerned about Zero Downtime Upgrades here. An old task (dispatched before this change) updating a distribution would only lock on the domain:distributions and a new one only on the single distribution. Since distributions themselves are rather shallow, I cannot think about a situation where this collision leads to real world impacts. But my lack of imagination here is no guarantee for correctness.

Thanks, I think this is the main caveat in the current approach.

From our look at the code, we see two ways to address the ZDU concern:

  1. Add shared-resource support to the async mixins, so unchanged-base_path distribution updates can keep the narrower instance lock while still overlapping with older broad-lock tasks during rollout.
  2. Keep the change local to distributions by overriding the update path there and adding the shared reservation only for that case.

Both approaches would keep the current concurrency improvement while restoring compatibility with older broad-lock tasks during mixed-version upgrades.

@dralley

dralley commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

and a new one only on the single distribution.

But only if it doesn't actually change the base path, right? Tasks that do touch base_path would retain the domain:distributions lock. That seems OK.

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.

4 participants