From c8c1870c97f7f7901a781004badaff68d2a4a5eb Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 12 Jan 2023 11:47:17 +0000 Subject: [PATCH] Prevent memory exhaustion when purging a large number of revisions Optimise determining whether a revision is the latest This no longer attempts to load the entire revision into memory to compare. Instead, we just check if any revisions created after this one exist (that aren't this one). --- CHANGELOG.txt | 1 + docs/releases/4.2.md | 1 + wagtail/management/commands/purge_revisions.py | 2 +- wagtail/models/__init__.py | 11 ++++++----- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 60fb26d1b2..12c97e0d31 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -70,6 +70,7 @@ Changelog * Fix: Prevent obstructing the outline around rich text fields (Thibaud Colas) * Fix: Page editor dropdowns now use indigo backgrounds like elsewhere in the admin interface (Thibaud Colas) * Fix: Allow parsing of multiple key/value pairs from string in `wagtail.search.utils.parse_query_string` (Beniamin Bucur) + * Fix: Prevent memory exhaustion when purging a large number of revisions (Jake Howard) * Docs: Add custom permissions section to permissions documentation page (Dan Hayden) * Docs: Add documentation for how to get started with contributing translations for the Wagtail admin (Ogunbanjo Oluwadamilare) * Docs: Officially recommend `fnm` over `nvm` in development documentation (LB (Ben) Johnston) diff --git a/docs/releases/4.2.md b/docs/releases/4.2.md index 5b277a041c..69870c632f 100644 --- a/docs/releases/4.2.md +++ b/docs/releases/4.2.md @@ -107,6 +107,7 @@ This feature was developed by Matt Westcott, and sponsored by [YouGov](https://y * Prevent obstructing the outline around rich text fields (Thibaud Colas) * Page editor dropdowns now use indigo backgrounds like elsewhere in the admin interface (Thibaud Colas) * Allow parsing of multiple key/value pairs from string in `wagtail.search.utils.parse_query_string` (Beniamin Bucur) + * Prevent memory exhaustion when purging a large number of revisions (Jake Howard) ### Documentation diff --git a/wagtail/management/commands/purge_revisions.py b/wagtail/management/commands/purge_revisions.py index 633a5156a8..495b074d07 100644 --- a/wagtail/management/commands/purge_revisions.py +++ b/wagtail/management/commands/purge_revisions.py @@ -60,7 +60,7 @@ def purge_revisions(days=None): deleted_revisions_count = 0 - for revision in purgeable_revisions: + for revision in purgeable_revisions.iterator(): # don't delete the latest revision for any page if not revision.is_latest_revision(): revision.delete() diff --git a/wagtail/models/__init__.py b/wagtail/models/__init__.py index 4cb0e4bdd4..9d37c04c25 100644 --- a/wagtail/models/__init__.py +++ b/wagtail/models/__init__.py @@ -2835,15 +2835,16 @@ class Revision(models.Model): # special case: a revision without an ID is presumed to be newly-created and is thus # newer than any revision that might exist in the database return True - latest_revision = ( - Revision.objects.filter( + + return ( + not Revision.objects.filter( base_content_type_id=self.base_content_type_id, object_id=self.object_id, + created_at__gte=self.created_at, ) - .order_by("-created_at", "-id") - .first() + .exclude(id=self.id) + .exists() ) - return latest_revision == self def delete(self): # Update revision_created fields for comments that reference the current revision, if applicable.