open-webui/backend/open_webui/utils
Classic298 d67bc4ffcd
perf: batch the file access check queries (#27383)
has_access_to_file runs for every non-owner file GET, per RAG file check and per shared-chat or model-attached file. Its final step called Models.get_models_by_user_id, which issued one grant query per non-owned workspace model, so a single file check on an instance with M workspace models cost M grant queries plus a group query, with the deny path always paying full price. Its collection_name step listed every knowledge base the user can access (itself one grant query per knowledge base) just to scan the list for one id. And get_accessible_folder_files repeated the whole pipeline per folder entry, refetching the caller's group memberships every time.

Three changes, all using parameters and helpers that already exist:
- Models.get_models_by_user_id resolves grants for all non-owned models in one get_accessible_resource_ids call and accepts prefetched user_group_ids.
- The collection_name check fetches the one referenced knowledge base and performs a single owner-or-grant check with the already-resolved group ids, preserving the write-requires-owner guard exactly (including its short-circuit before any grant query).
- get_accessible_folder_files resolves group ids once and threads them through every per-entry check.

Benchmark:

| metric | before | after |
| --- | --- | --- |
| filter loop CPU, 300 workspace models (queries stubbed) | 47 us | 19 us |
| grant queries per file-access check, M workspace models | M | 1 |
| group membership queries per folder listing, F files | F | 1 |

The stubbed CPU row understates the win: each removed query in the other two rows was a real database round trip.

Functionally verified with stubbed accessors: owned plus granted models are returned with owned ids excluded from the batch query; model-attached file access resolves through the batched path; the collection_name path does one KB fetch and one grant check with no full listing; a missing KB falls through; write access via a KB still requires the KB owner to own the file and short-circuits before the grant query; folder listings fetch groups exactly once.
2026-07-23 17:50:08 -05:00
..
access_control perf: batch the file access check queries (#27383) 2026-07-23 17:50:08 -05:00
images refac 2026-07-01 02:48:29 -05:00
mcp refac 2026-06-29 11:56:00 -05:00
telemetry refac(telemetry): drop deprecated semconv SpanAttributes subclass (#25784) 2026-06-29 02:05:34 -05:00
actions.py fix: enforce action availability and model access on the chat action route (#27243) 2026-07-23 12:23:05 -04:00
anthropic.py refac 2026-07-23 04:16:14 -04:00
asgi_middleware.py perf: cut per-request database session overhead (#27385) 2026-07-23 17:49:48 -05:00
audit.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
auth.py refac 2026-07-23 12:48:23 -04:00
automations.py refac 2026-07-16 01:34:50 -04:00
calendar.py feat: add repeat/recurrence dropdown to calendar event modal (#25865) 2026-06-29 02:16:19 -05:00
channels.py refac 2026-03-17 17:58:01 -05:00
chat.py Enforce per-model access on arena fallback before bypass_filter dispatch (#26046) 2026-06-16 22:45:42 +02:00
chat_fork.py refac 2026-07-23 02:54:56 -04:00
code_interpreter.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
context_compaction.py refac 2026-07-23 02:54:56 -04:00
embeddings.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
files.py perf(images): offload validate_url() DNS resolution with asyncio.to_thread (#25825) 2026-06-29 02:31:24 -05:00
filter.py refac 2026-07-23 12:48:14 -04:00
groups.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
headers.py feat: forward client User-Agent to model backends via {{USER_AGENT}} placeholder (#26333) 2026-06-29 05:58:19 -05:00
logger.py chore: format 2026-06-01 13:56:55 -07:00
memory.py refac 2026-07-01 03:35:46 -05:00
middleware.py fix: persist upstream streaming error lines by awaiting the message upsert (#27365) 2026-07-23 17:49:18 -05:00
misc.py refac 2026-06-29 13:03:14 -05:00
models.py perf: halve function-table queries in get_all_models (#27230) 2026-07-23 12:11:51 -04:00
notifications.py refac 2026-07-16 01:37:21 -04:00
oauth.py refac 2026-07-01 02:57:29 -05:00
payload.py refac 2026-06-29 00:18:40 -05:00
pdf_generator.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
plugin.py refac 2026-07-09 17:28:34 -05:00
rate_limit.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
redis.py fix(redis): use await asyncio.sleep() instead of time.sleep() in async generator (#25823) 2026-06-29 02:25:46 -05:00
response.py refac 2026-06-23 23:35:44 +02:00
sanitize.py refac 2026-03-17 17:58:01 -05:00
security_headers.py perf: stop recomputing static work in per-response ASGI middlewares (#27229) 2026-07-23 12:29:01 -04:00
session_pool.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
subagents.py chore: format 2026-07-20 22:11:42 -04:00
task.py refac 2026-06-19 00:16:06 +02:00
terminals.py refac 2026-07-10 18:32:21 -05:00
timers.py chore: format 2026-07-20 22:11:42 -04:00
tools.py refac 2026-07-16 00:58:34 -04:00
validate.py chore: format 2026-06-01 13:56:55 -07:00
valves.py refac 2026-06-29 12:29:10 -05:00
webhook.py refac 2026-06-29 13:03:14 -05:00