mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-07-30 23:55:59 +00:00
fix(benchmark): reuse seeded data in profile instead of reseeding
_handle_profile unconditionally called seed_benchmark_dataset every run, colliding with an IntegrityError against data seeded by a prior seed/profile call. Look up the existing perf_target user instead, matching _handle_run's already-correct pattern, and raise a CommandError pointing at `seed` if no dataset exists. Scenario.run/queryset_for_explain now take a User directly instead of a SeededData, since only data.users[0] (perf_target) was ever used. profile no longer seeds, so it drops the --tier dependency: the printed line and history entry no longer include a tier/(tier=...) suffix, and --tier's help text now only mentions `seed`.
This commit is contained in:
@@ -27,7 +27,7 @@ class Command(BaseCommand):
|
||||
"--tier",
|
||||
choices=["home", "medium", "large"],
|
||||
default="medium",
|
||||
help="Dataset scale tier for `seed` and `profile` (default: medium).",
|
||||
help="Dataset scale tier for `seed` (default: medium).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--reset",
|
||||
@@ -131,11 +131,12 @@ class Command(BaseCommand):
|
||||
)
|
||||
|
||||
def _handle_profile(self, options: dict[str, Any]) -> None:
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from paperless_benchmark.db import capture_explain
|
||||
from paperless_benchmark.harness import run_profile
|
||||
from paperless_benchmark.results import append_history
|
||||
from paperless_benchmark.scenarios import get as get_scenario
|
||||
from paperless_benchmark.seeding import seed_benchmark_dataset
|
||||
|
||||
if not options["scenario"]:
|
||||
raise CommandError(
|
||||
@@ -143,23 +144,32 @@ class Command(BaseCommand):
|
||||
)
|
||||
|
||||
scenario = get_scenario(options["scenario"])
|
||||
data = seed_benchmark_dataset(options["tier"], seed=options["seed"])
|
||||
|
||||
profile = run_profile(lambda: scenario.run(data), repeat=options["repeat"])
|
||||
user_model = get_user_model()
|
||||
try:
|
||||
perf_target = user_model.objects.get(username="perf_target")
|
||||
except user_model.DoesNotExist as e:
|
||||
raise CommandError(
|
||||
"No benchmark dataset found. Run `manage.py benchmark seed` first.",
|
||||
) from e
|
||||
|
||||
profile = run_profile(
|
||||
lambda: scenario.run(perf_target),
|
||||
repeat=options["repeat"],
|
||||
)
|
||||
self.stdout.write(
|
||||
f"{scenario.name}: best={profile.best_seconds:.4f}s "
|
||||
f"queries={profile.query_count} (tier={options['tier']})",
|
||||
f"queries={profile.query_count}",
|
||||
)
|
||||
|
||||
if options["explain"] and scenario.queryset_for_explain is not None:
|
||||
plan = capture_explain(scenario.queryset_for_explain(data))
|
||||
plan = capture_explain(scenario.queryset_for_explain(perf_target))
|
||||
self.stdout.write(plan)
|
||||
|
||||
append_history(
|
||||
{
|
||||
"mode": "profile",
|
||||
"scenario": scenario.name,
|
||||
"tier": options["tier"],
|
||||
"best_seconds": profile.best_seconds,
|
||||
"query_count": profile.query_count,
|
||||
},
|
||||
|
||||
@@ -8,17 +8,16 @@ from typing import Any
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import QuerySet
|
||||
|
||||
from paperless_benchmark.seeding import SeededData
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Scenario:
|
||||
name: str
|
||||
describe: str
|
||||
run: Callable[[SeededData], Any]
|
||||
queryset_for_explain: Callable[[SeededData], QuerySet] | None = None
|
||||
run: Callable[[User], Any]
|
||||
queryset_for_explain: Callable[[User], QuerySet] | None = None
|
||||
|
||||
|
||||
_SCENARIOS: dict[str, Scenario] = {}
|
||||
@@ -44,11 +43,10 @@ def all_scenarios() -> tuple[Scenario, ...]:
|
||||
return tuple(_SCENARIOS.values())
|
||||
|
||||
|
||||
def _guardian_visibility_query_run(data: SeededData) -> list[int]:
|
||||
def _guardian_visibility_query_run(user: User) -> list[int]:
|
||||
from documents.models import Document
|
||||
from documents.permissions import get_objects_for_user_owner_aware
|
||||
|
||||
user = data.users[0]
|
||||
return list(
|
||||
get_objects_for_user_owner_aware(
|
||||
user,
|
||||
@@ -58,11 +56,10 @@ def _guardian_visibility_query_run(data: SeededData) -> list[int]:
|
||||
)
|
||||
|
||||
|
||||
def _guardian_visibility_query_queryset(data: SeededData) -> QuerySet:
|
||||
def _guardian_visibility_query_queryset(user: User) -> QuerySet:
|
||||
from documents.models import Document
|
||||
from documents.permissions import get_objects_for_user_owner_aware
|
||||
|
||||
user = data.users[0]
|
||||
return get_objects_for_user_owner_aware(user, "documents.view_document", Document)
|
||||
|
||||
|
||||
@@ -80,11 +77,10 @@ register(
|
||||
)
|
||||
|
||||
|
||||
def _permitted_document_ids_run(data: SeededData) -> list[int]:
|
||||
def _permitted_document_ids_run(user: User) -> list[int]:
|
||||
from documents.models import Document
|
||||
from documents.permissions import permitted_document_ids
|
||||
|
||||
user = data.users[0]
|
||||
return list(
|
||||
Document.objects.filter(id__in=permitted_document_ids(user)).values_list(
|
||||
"id",
|
||||
@@ -93,11 +89,10 @@ def _permitted_document_ids_run(data: SeededData) -> list[int]:
|
||||
)
|
||||
|
||||
|
||||
def _permitted_document_ids_queryset(data: SeededData) -> QuerySet:
|
||||
def _permitted_document_ids_queryset(user: User) -> QuerySet:
|
||||
from documents.models import Document
|
||||
from documents.permissions import permitted_document_ids
|
||||
|
||||
user = data.users[0]
|
||||
return Document.objects.filter(id__in=permitted_document_ids(user))
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user