Skip to content

perf(datasets): batch wildcard exclusions in subject set subtraction - #3395

Merged
josephschorr merged 2 commits into
authzed:mainfrom
dantrapp:perf/lookup-subjects-batching
Oct 5, 2026
Merged

josephschorr merged 2 commits into
authzed:mainfrom
dantrapp:perf/lookup-subjects-batching

Conversation

@dantrapp

@dantrapp dantrapp commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

LookupSubjects repeatedly copies a growing exclusion list when subtracting concrete subjects from a wildcard. SubtractAll now builds that list once, preserving caveat expressions and resource provenance through the existing constructors. This makes exclusion construction linear in the existing exclusions and removed subjects. Wildcard subtraction and zero/one-subject cases retain the existing path. AsSlice also allocates its known capacity once.

Adds differential tests against sequential subtraction, input-mutation and resource-tracking checks, and benchmarks for subject-set subtraction and dispatched wildcard lookups.

Measured through the public gRPC API with PostgreSQL 16.11, Go 1.26.8, and enabled dispatch caches on an Apple M4:

Workload Baseline p95 Patched p95 Baseline allocated/lookup Patched allocated/lookup
5,000 exclusions, changing revisions 88.7 ms 11.4 ms 111.5 MB 3.6 MB
5,000 exclusions, cached snapshot 7.1 ms 7.3 ms 1.35 MB 1.35 MB
1,000 concrete members minus 500 users 6.7 ms 6.8 ms 1.24 MB 1.22 MB

Values are medians across three runs of 60 requests at 10 requests/second, with a fresh server per case. The first case uses fully consistent reads with concurrent writes; its per-run p95 ranges were 75.5–93.0 ms before and 9.7–13.6 ms after. Allocation includes concurrent writes and background work. The controls showed no consistent latency change. These are synthetic graphs on one shared local machine.

Reproduction commands, fixtures, pinned revisions, and raw measurements.

Validation: 106 unit-test packages passed; race checks passed for datasets, development membership, graph, and dispatch caching; golangci-lint reported no issues in the changed packages. All 96 PostgreSQL fixture documents returned the exact expected subjects. Docker-dependent tests were not run because Docker was unavailable locally.

Fixes #3394.

@dantrapp
dantrapp requested a review from a team as a code owner October 5, 2026 00:29
@github-actions github-actions Bot added the area/tooling Affects the dev or user toolchain (e.g. tests, ci, build tools) label Oct 5, 2026
@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@dantrapp

dantrapp commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

authzedbot added a commit to authzed/cla that referenced this pull request Oct 5, 2026
Comment thread internal/datasets/basesubjectset.go Outdated
}
return
}
// Build the exclusions once instead of copying the growing slice for each subject.

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.

newline before this line

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

NP. Done.

for _, otherSubject := range other.AsSlice() {
bss.Subtract(otherSubject)
wildcard, hasWildcard := bss.wildcard.get()
if !hasWildcard || other.wildcard.getOrNil() != nil || len(other.concrete) < 2 {

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.

Add a comment explaining here exactly what's being done: BaseSubjectSet is very complex, so we require detailed comments

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added an explanation of which cases can be batched and why subtracting another wildcard stays on the existing path.

exclusions := make([]T, 0, len(existingExclusions)+len(other.concrete))
matched := make(map[string]struct{}, min(len(existingExclusions), len(other.concrete)))
for _, exclusion := range existingExclusions {
if removing, ok := other.concrete[exclusion.GetSubjectId()]; ok {

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.

ditto in here for comments

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added a caveat example here, including the unconditional case, and explained why we keep both source subjects.

return cloned
}

func BenchmarkSubjectSetSubtractAll(b *testing.B) {

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.

Add some pre-defined, readable unit tests (in their own table-driven test)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. Added a table-driven test with the inputs and expected results written out for each case.

@josephschorr josephschorr 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.

LGTM

@josephschorr
josephschorr merged commit 983ff47 into authzed:main Oct 5, 2026
43 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area/tooling Affects the dev or user toolchain (e.g. tests, ci, build tools)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LookupSubjects copies wildcard exclusions quadratically when subtracting concrete subjects

2 participants