mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-09-11 20:28:01 +00:00
Performance: batch permission assignment in bulk set_permissions (#13806)
* Perf: batch guardian permission assignment in bulk-edit bulk_edit.set_permissions and BulkEditObjectPermissionsView both looped documents/objects and called set_permissions_for_object per object, which itself calls guardian's assign_perm/remove_perm once per (object, user) pair -- ~10-20+ queries per object, scaling with selection size. Added set_permissions_for_objects, a bulk equivalent that resolves existing permission holders once across the whole batch (not once per object) and applies changes with a small, batch-size-independent number of queries per action instead of one per (object, user) pair. * Perf: avoid unnecessary full-row fetches in batch permission assignment set_permissions_for_objects now takes a model + pks instead of instances, and identity filtering resolves straight to ids, so bulk-editing permissions no longer materializes full Document/User/Group rows just to read their pk/id. Row construction for bulk_create is also chunked to bound peak memory for very large "apply to all" operations. * Fix: use .distinct() for existing-grant lookup, drop flaky query-count invariant tests .distinct() lets the database dedupe identity ids server-side instead of transferring one row per (object, grantee) match and deduping in Python -- was the dominant cost on a large selection with existing grants. Also replaced the two query-count-equality tests (bulk_edit and the bulk_edit_objects API path) with plain functional-correctness checks at both batch sizes. Hopefully stops that flake. * Mark empty-pks early-return in set_permissions_for_objects as no-cover Defensive guard for an edge case (all requested pks already gone/invalid) rather than a path normal usage exercises; matches the existing pragma: no cover convention elsewhere in this file. * Perf: drop speculative row-chunking in bulk permission assignment, keep the query-batching fix * Resolve every permission action before applying any of them This fixes the existing issue and resolves the Copilot comment * Assert permission assignment does not scale with selection size The two batching tests only checked that permissions came out correct at 5 and 50 objects, so reverting to the old per-object loop would still have passed. Check sizes as well to prevent that
This commit is contained in:
@@ -28,7 +28,7 @@ from documents.models import DocumentType
|
||||
from documents.models import PaperlessTask
|
||||
from documents.models import StoragePath
|
||||
from documents.models import Tag
|
||||
from documents.permissions import set_permissions_for_object
|
||||
from documents.permissions import set_permissions_for_objects
|
||||
from documents.plugins.helpers import DocumentsStatusManager
|
||||
from documents.tasks import bulk_update_documents
|
||||
from documents.tasks import consume_file
|
||||
@@ -433,10 +433,13 @@ def set_permissions(
|
||||
else:
|
||||
qs.update(owner=owner)
|
||||
|
||||
for doc in qs:
|
||||
set_permissions_for_object(permissions=set_permissions, object=doc, merge=merge)
|
||||
|
||||
affected_docs = list(qs.values_list("pk", flat=True))
|
||||
set_permissions_for_objects(
|
||||
permissions=set_permissions,
|
||||
model=Document,
|
||||
pks=affected_docs,
|
||||
merge=merge,
|
||||
)
|
||||
|
||||
bulk_update_documents.apply_async(
|
||||
kwargs={"document_ids": affected_docs},
|
||||
|
||||
Reference in New Issue
Block a user