#36168: migration plan in the context of squashmigrations has too many leaves
-------------------------------------+-------------------------------------
Reporter: Klaas van Schelven | Type:
| Uncategorized
Status: new | Component:
| Migrations
Version: 5.1 | Severity: Normal
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
I managed to debug my way to the broken part of the code, but did not
manage to find a nice clean reproduction. Hence the following report
starts with broken code and only then explains the problem, which is the
unusual order.
[https://github.com/django/django/blob/b1324a680add78de24c763911d0eefa19b9263bc/django/db/migrations/executor.py#L49
here's the broken code]
This is wrong because it mutates the state on the `MigrationExecutor`,
i.e. in certain conditions a different graph (without the pruning of
`replace_migrations`) is set "globally" on the `MigrationExecutor`.
But `migration_plan` (the function of which the broken code is part) is
called _twice_ in at least some flows. In particular: first as part of
`migrate`, and then as part of `_create_project_state`. This means that,
for flows where the broken code is called in the first call to
`migration_plan` (for presumably good reasons, as per the comment above
it), the construction of the second plan uses a graph that is too large,
causing a failure in some cases.
This fails in the following combination of conditions:
1. a project with squashed migrations in more than one app
2. where the squashed migrations do not have follow-up migrations (i.e.
when the graph is not simplified for replacements, both the squashing
migration and the last migration it replaces show up as leaf nodes)
3. explicit migration to a replaced migration from the command line.
because of the explicit migration to a replaced migration (3) the graph is
updated in the "wrong code" as per the comment. Then, when trying to
`_create_project_state` the graph contains leaf nodes for both the
original and squashed paths, which means that some things in the project-
state-creation happen doubly, which fails.
I have encountered this while working on [https://www.bugsink.com/
Bugsink, a self-hosted Error Tracker], on
[https://github.com/bugsink/bugsink/tree/0b42d3ff1e0344a79bf3784c7cf2d68ea0d20a29
this commit]. I have not been able to distill a more clean PoC that
actually exhibits failure though.
Replacing the mutation with something that leaves the loader untouched
(ugly version below) fixes the problem though.
{{{
old_loader = self.loader
self.loader = MigrationLoader(self.connection)
self.loader.replace_migrations = False
self.loader.build_graph()
result = self.migration_plan(targets,
clean_start=clean_start)
self.loader = old_loader
return result
}}}
[https://code.djangoproject.com/ticket/36166#ticket this ticket may or may
not be related]
--
Ticket URL: <https://code.djangoproject.com/ticket/36168>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/django-updates/01070194d000d932-218509bc-a160-459f-b093-3637a3689db6-000000%40eu-central-1.amazonses.com.