You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[v3.1.2] Cover letters created before migrating to v3 show up separatly in patch list #556
changed the title [-][v3.1.2] Many cover letters are no longer part of their series after migration from v2.2[/-][+][v3.1.2] Cover letters are no longer part of their series after migration from v2.2[/+]on Aug 16, 2023
changed the title [-][v3.1.2] Cover letters are no longer part of their series after migration from v2.2[/-][+][v3.1.2] Cover letters created before migrating to v3 show up separatly in patch list[/+]on Aug 20, 2023
New replies to cover letters created prior to the migration from v2 to v3 will not appear in the cover letter that is part of the series and will not trigger a cover-comment-created event.
@stephenfin, do you think this issue could be resolved in a new migration? Rolling back could be problematic because the recent migrations aren't reversible. Any suggestion?
First pass suggests I've missed something in the migration. That migration got rid of the Submission model, which Patch and Cover inherited from (read: JOINed to) in favour of wholly separate models. My guess is that we've ended up with a row in both tables.
Are new cover letters to new series (created after the migration) getting linked correctly?
Yes new ones are linked correctly.
New cover letters (created after the migration) only have a /project/<Project>/cover/<Message-Id> web url.
Old cover letters (created before the migration) have /project/<Project>/cover/<Message-Id>and/project/<Project>/patch/<Message-Id> web urls.
When someone replies to old cover letters, the reply appears in the /project/<Project>/patch/<Message-Id> url, which isn't part of a series.
First pass suggests I've missed something in the migration. That migration got rid of the Submission model, which Patch and Cover inherited from (read: JOINed to) in favour of wholly separate models. My guess is that we've ended up with a row in both tables.
Yeah, looks like it's this: I forgot to clean up the old cover letter-related entries in the patchwork_submission table before it got renamed to patchwork_patch (migration 0043).
@alialnu Can you check something for me: do the following commands returns the same count?
SELECTCOUNT(patch.id) FROM patchwork_patch patch WHERE ISNULL(patch.state_id);
SELECTCOUNT(cover.id) FROM patchwork_cover cover;
And maybe for safety, check the exact IDs also.
SELECTpatch.idFROM patchwork_patch patch WHERE ISNULL(patch.state_id);
SELECTcover.idFROM patchwork_cover cover;
Cover letters don't have a state but patches always do, so in theory any entry in patchwork_patch with a null state_id column should be left-over cover letters. I'd like to sanity check this against a real deployment though.
If this works, our apparent fix would be to identify any rows in patchwork_patch_comment that have foreign keys pointing to one of these rows in patchwork_patch, copy them to patchwork_covercomment, then delete the offending rows in patchwork_patch(which should cause the patchwork_patchcomment rows to be deleted since we have a CASCADE in place) after we've deleted the rows in patchwork_patchcomment since Django doesn't do database-level cascading. Sound reasonable?
# copy any recent patch comments that should have been assigned to a cover letter insteadINSERT INTO patchwork_covercomment (msgid, date, headers, content, cover_id, submitter_id)
SELECT msgid, date, headers, content, patch_id, submitter_id
FROM patchwork_patchcomment
WHEREpatchwork_patchcomment.patch_idIN (
SELECTpatch.idFROM patchwork_patch patch WHERE ISNULL(patch.state_id)
);
# delete the duplicate patch commentsDELETE patch_comment
FROM patchwork_patchcomment patch_comment
WHEREpatch_comment.patch_idIN (
SELECTpatch.idFROM patchwork_patch patch WHERE ISNULL(patch.state_id)
);
# delete the duplicate patchesDELETE patch FROM patchwork_patch patch WHERE ISNULL(patch.state_id);
Assuming so, I can codify this in a migration script and push a new migration. The only thing is that Django doesn't appear to provide a mechanism to insert a migration between two older migrations (unlike Alembic) so you're either going to need to update to current HEAD, wait for a new release, or run it manually (it should be idempotent so there'll be no issues if you did it manually and later upgraded to a release with this migration in it)
I've opened a bug against Django since this isn't the behavior I expected. I expected the deletion of the CoverLetter model to drop all rows in the parent Submission table. This clearly didn't happen.
@alialnu Can you check something for me: do the following commands returns the same count?
I forgot to mention that I'm using postgresql. I made some changes to the queries:
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL;
id
--------6129277881
[..]
129709129712
(8138 rows)
SELECTcover.idFROM patchwork_cover cover;
id
--------12
[..]
129709129712
(8222 rows)
They aren't returning the same count.
EDIT: Effectively this query:
SELECTpatch_comment.idFROM patchwork_patchcomment patch_comment
WHEREpatch_comment.patch_idIN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
id
--------162805162984
[..]
163347163359
(26 rows)
I think the following script should do the trick.
Removing duplicate patch comments is failing for me:
# copy any recent patch comments that should have been assigned to a cover letter insteadINSERT INTO patchwork_covercomment (msgid, date, headers, content, cover_id, submitter_id)
SELECT msgid, date, headers, content, patch_id, submitter_id
FROM patchwork_patchcomment
WHEREpatchwork_patchcomment.patch_idIN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
Output:
INSERT 0 26
# delete the duplicate patch commentsDELETEFROM patchwork_patchcomment AS patch_comment
WHEREpatch_comment.patch_idIN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
Output:
ERROR: update or delete on table "patchwork_patchcomment" violates foreign key constraint "patchwork_event_patch_comment_id_4123011e_fk_patchwork" on table "patchwork_event"
DETAIL: Key (id)=(162805) is still referenced from table "patchwork_event".
@alialnu Can you check something for me: do the following commands returns the same count?
I forgot to mention that I'm using postgresql. I made some changes to the queries:
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL;
id
--------6129277881
[..]
129709129712
(8138 rows)
SELECTcover.idFROM patchwork_cover cover;
id
--------12
[..]
129709129712
(8222 rows)
They aren't returning the same count.
Ah, right, they will be different since you have new cover letters. You probably need to add a limit to this. We don't track our own created_at/updated_at fields so we need to use date as a stand-in. This should do the trick (or at least the PostgreSQL equivalent will):
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL;
SELECTcover.idFROM patchwork_cover cover
WHEREcover.date<= (
SELECTMAX(patch.date) FROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
I'm pretty confident that filtering on null state_id will do the trick now though, with what you've already provided.
Whoops, I forgot about the events. How about if you add the following after the first step?
# migrate any erroneous patch-comment-created events to cover-comment-created eventsUPDATE patchwork_event
SET cover_id = patch_id, category ='cover-comment-created', patch_id =NULLWHERE patch_id IN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
Deleting duplicate patch comments still fails:
INSERT INTO patchwork_covercomment (msgid, date, headers, content, cover_id, submitter_id)
SELECT msgid, date, headers, content, patch_id, submitter_id
FROM patchwork_patchcomment
WHEREpatchwork_patchcomment.patch_idIN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
INSERT 0 26
UPDATE patchwork_event
SET cover_id = patch_id, category ='cover-comment-created', patch_id =NULLWHERE patch_id IN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
UPDATE 26
DELETEFROM patchwork_patchcomment AS patch_comment
WHEREpatch_comment.patch_idIN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
ERROR: update or delete on table "patchwork_patchcomment" violates foreign key constraint "patchwork_event_patch_comment_id_4123011e_fk_patchwork" on table "patchwork_event"
DETAIL: Key (id)=(162805) is still referenced from table "patchwork_event".
ERROR: update or delete on table "patchwork_patchcomment" violates foreign key constraint "patchwork_event_patch_comment_id_4123011e_fk_patchwork" on table "patchwork_event"
DETAIL: Key (id)=(162805) is still referenced from table "patchwork_event".
That field should have been unset in the previous statement. Perhaps it needs to be split into two statements. Can you check if it was unset?
SELECT cover_id, patch_id FROM patchwork_event WHERE id=162805;
By the way, I noticed that new cover IDs started counting from 1 after the migration: patches.dpdk.org/api/covers/1 The last cover ID was 40691 before the migration: patches.dpdk.org/api/covers/40691 I guess it's an expected side effect of removing the old CoverLetter model?
Yes, that's expected behavior. I'm going to guess PostgreSQL was restarted at some point? I know MySQL restarts the autoincrement counter at the lowest available value when it's restarted. It shouldn't matter since the ID has no significance and we've intentionally started hiding it in recent releases (at least in the web UI: the REST API and deprecated XML-RPC API still need work)
# migrate any erroneous patch-comment-created events to cover-comment-created eventsUPDATE patchwork_event
SET cover_id = patch_id, category ='cover-comment-created', patch_id =NULLWHERE patch_id IN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
with:
# migrate any erroneous patch-comment-created events to cover-comment-created eventsUPDATE patchwork_event
SET
cover_id = patch_id,
cover_comment_id = patch_comment_id,
category ='cover-comment-created',
patch_id =NULL,
patch_comment_id =NULLWHERE patch_id IN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
I get a different error right now:
UPDATE patchwork_event
SET
cover_id = patch_id,
cover_comment_id = patch_comment_id,
category ='cover-comment-created',
patch_id =NULL,
patch_comment_id =NULLWHERE patch_id IN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
ERROR: insert or update on table "patchwork_event" violates foreign key constraint "patchwork_event_cover_comment_id_861b3ec2_fk_patchwork"
DETAIL: Key (cover_comment_id)=(162801) is not present in table "patchwork_covercomment".
By the way, I noticed that new cover IDs started counting from 1 after the migration: patches.dpdk.org/api/covers/1 The last cover ID was 40691 before the migration: patches.dpdk.org/api/covers/40691 I guess it's an expected side effect of removing the old CoverLetter model?
Yes, that's expected behavior. I'm going to guess PostgreSQL was restarted at some point? I know MySQL restarts the autoincrement counter at the lowest available value when it's restarted. It shouldn't matter since the ID has no significance and we've intentionally started hiding it in recent releases (at least in the web UI: the REST API and deprecated XML-RPC API still need work)
Thanks for the confirmation. I don't recall restarting the database server. The counter was reset right after the migration.
Lovely. So when we did the first step in the migration
# copy any recent patch comments that should have been assigned to a cover letter insteadINSERT INTO patchwork_covercomment (msgid, date, headers, content, cover_id, submitter_id)
SELECT msgid, date, headers, content, patch_id, submitter_id
FROM patchwork_patchcomment
WHEREpatchwork_patchcomment.patch_idIN (
SELECTpatch.idFROM patchwork_patch patch WHERE ISNULL(patch.state_id)
);
we will have got a new, likely different ID for each new entry in patchwork_covercomment. As such, we need to set cover_comment_id to the ID of the row in patchwork_covercomment which corresponds to the old patchwork_patchcomment row. I'm not actually entirely sure how to do that. The best I could come up with is this horribly inefficient query.
# migrate any erroneous patch-comment-created events to cover-comment-created eventsUPDATE patchwork_event
SET
cover_id = patch_id,
cover_comment_id = (
SELECTpatchwork_covercomment.idFROM patchwork_covercomment
INNER JOIN patchwork_patchcomment
ONpatchwork_covercomment.msgid=patchwork_patchcomment.msgidWHEREpatchwork_patchcomment.id=patchwork_event.patch_comment_id
),
category ='cover-comment-created',
patch_id =NULL,
patch_comment_id =NULLWHERE patch_id IN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
I've no idea if that will work or not as I still haven't got a full reproducer locally for these follow-up issues.
we will have got a new, likely different ID for each new entry in patchwork_covercomment. As such, we need to set cover_comment_id to the ID of the row in patchwork_covercomment which corresponds to the old patchwork_patchcomment row. I'm not actually entirely sure how to do that. The best I could come up with is this horribly inefficient query.
The UPDATE statement fails with:
ERROR: more than one row returned by a subquery used as an expression
I'm having a difficult time constructing a query to find the problematic IDs though.
Sorry for the late response @stephenfin, I missed your last suggestion.
The suggested query failed with:
ERROR: column "event" of relation "patchwork_event" does not exist
LINE 3: event.cover_id = event.patch_id,
I got it to work with these changes:
UPDATE patchwork_event AS event
SET
cover_id =event.patch_id,
cover_comment_id =cover_comment.id,
category ='cover-comment-created',
patch_id =NULLFROM patchwork_patchcomment patch_comment
INNER JOIN patchwork_covercomment cover_comment
ONpatch_comment.msgid=cover_comment.msgidWHEREpatch_comment.id=event.patch_comment_idANDevent.patch_idIN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
UPDATE 26
Removing duplicate patch comments still fails though:
DELETEFROM patchwork_patchcomment AS patch_comment
WHEREpatch_comment.patch_idIN (
SELECTpatch.idFROM patchwork_patch patch WHEREpatch.state_id IS NULL
);
ERROR: update or delete on table "patchwork_patchcomment" violates foreign key constraint "patchwork_event_patch_comment_id_4123011e_fk_patchwork" on table "patchwork_event"
DETAIL: Key (id)=(162805) is still referenced from table "patchwork_event".
Activity
[-][v3.1.2] Many cover letters are no longer part of their series after migration from v2.2[/-][+][v3.1.2] Cover letters are no longer part of their series after migration from v2.2[/+][-][v3.1.2] Cover letters are no longer part of their series after migration from v2.2[/-][+][v3.1.2] Cover letters created before migrating to v3 show up separatly in patch list[/+]alialnu commentedon Aug 21, 2023
New replies to cover letters created prior to the migration from v2 to v3 will not appear in the cover letter that is part of the series and will not trigger a
cover-comment-createdevent.alialnu commentedon Aug 21, 2023
@stephenfin, do you think this issue could be resolved in a new migration? Rolling back could be problematic because the recent migrations aren't reversible. Any suggestion?
stephenfin commentedon Aug 24, 2023
In theory, yes, migrations can fix anything in the database. I need to find time to look into this though. Perhaps this weekend.
Are new cover letters to new series (created after the migration) getting linked correctly?
stephenfin commentedon Aug 24, 2023
First pass suggests I've missed something in the migration. That migration got rid of the
Submissionmodel, whichPatchandCoverinherited from (read:JOINed to) in favour of wholly separate models. My guess is that we've ended up with a row in both tables.alialnu commentedon Aug 24, 2023
Yes new ones are linked correctly.
New cover letters (created after the migration) only have a
/project/<Project>/cover/<Message-Id>web url.Old cover letters (created before the migration) have
/project/<Project>/cover/<Message-Id>and/project/<Project>/patch/<Message-Id>web urls.When someone replies to old cover letters, the reply appears in the
/project/<Project>/patch/<Message-Id>url, which isn't part of a series.stephenfin commentedon Aug 24, 2023
Yeah, looks like it's this: I forgot to clean up the old cover letter-related entries in the
patchwork_submissiontable before it got renamed topatchwork_patch(migration0043).@alialnu Can you check something for me: do the following commands returns the same count?
And maybe for safety, check the exact IDs also.
Cover letters don't have a state but patches always do, so in theory any entry in
patchwork_patchwith a nullstate_idcolumn should be left-over cover letters. I'd like to sanity check this against a real deployment though.If this works, our apparent fix would be to identify any rows in
patchwork_patch_commentthat have foreign keys pointing to one of these rows inpatchwork_patch, copy them topatchwork_covercomment, then delete the offending rows inpatchwork_patch(which should cause theafter we've deleted the rows inpatchwork_patchcommentrows to be deleted since we have a CASCADE in place)patchwork_patchcommentsince Django doesn't do database-level cascading. Sound reasonable?EDIT: Effectively this query:
stephenfin commentedon Aug 24, 2023
I think the following script should do the trick.
Assuming so, I can codify this in a migration script and push a new migration. The only thing is that Django doesn't appear to provide a mechanism to insert a migration between two older migrations (unlike Alembic) so you're either going to need to update to current
HEAD, wait for a new release, or run it manually (it should be idempotent so there'll be no issues if you did it manually and later upgraded to a release with this migration in it)stephenfin commentedon Aug 24, 2023
I've opened a bug against Django since this isn't the behavior I expected. I expected the deletion of the
CoverLettermodel to drop all rows in the parentSubmissiontable. This clearly didn't happen.https://code.djangoproject.com/ticket/34796
alialnu commentedon Aug 24, 2023
Thanks @stephenfin for helping with this,
I forgot to mention that I'm using postgresql. I made some changes to the queries:
They aren't returning the same count.
Removing duplicate patch comments is failing for me:
Output:
Output:
stephenfin commentedon Aug 24, 2023
Whoops, I forgot about the events. How about if you add the following after the first step?
stephenfin commentedon Aug 24, 2023
Ah, right, they will be different since you have new cover letters. You probably need to add a limit to this. We don't track our own
created_at/updated_atfields so we need to usedateas a stand-in. This should do the trick (or at least the PostgreSQL equivalent will):I'm pretty confident that filtering on null
state_idwill do the trick now though, with what you've already provided.1 remaining item
alialnu commentedon Aug 24, 2023
Deleting duplicate patch comments still fails:
stephenfin commentedon Aug 26, 2023
That field should have been unset in the previous statement. Perhaps it needs to be split into two statements. Can you check if it was unset?
alialnu commentedon Aug 26, 2023
That id belongs to a
check-createdevent, so I guess it shouldn't have been affected by the previous query:alialnu commentedon Aug 26, 2023
By the way,
I noticed that new cover IDs started counting from
1after the migration:https://patches.dpdk.org/api/covers/1/
The last cover ID was
40691before the migration:https://patches.dpdk.org/api/covers/40691/
I guess it's an expected side effect of removing the old
CoverLettermodel?stephenfin commentedon Aug 30, 2023
Apologies:
162805refers to a row in thepatchwork_patchcommenttable (I see https://patches.dpdk.org/comment/162805/ resolves to https://patches.dpdk.org/project/dpdk/patch/cover.1640838702.git.songyl@ramaxel.com/#162805). We need to migrate thepatch_comment_idfield tocover_comment_idfield, in addition to migratingpatch_idtocover_id.Let's replace:
with:
stephenfin commentedon Aug 30, 2023
Yes, that's expected behavior. I'm going to guess PostgreSQL was restarted at some point? I know MySQL restarts the autoincrement counter at the lowest available value when it's restarted. It shouldn't matter since the ID has no significance and we've intentionally started hiding it in recent releases (at least in the web UI: the REST API and deprecated XML-RPC API still need work)
alialnu commentedon Aug 30, 2023
I get a different error right now:
alialnu commentedon Aug 30, 2023
Thanks for the confirmation. I don't recall restarting the database server. The counter was reset right after the migration.
stephenfin commentedon Sep 4, 2023
Lovely. So when we did the first step in the migration
we will have got a new, likely different ID for each new entry in
patchwork_covercomment. As such, we need to setcover_comment_idto the ID of the row inpatchwork_covercommentwhich corresponds to the oldpatchwork_patchcommentrow. I'm not actually entirely sure how to do that. The best I could come up with is this horribly inefficient query.I've no idea if that will work or not as I still haven't got a full reproducer locally for these follow-up issues.
stephenfin commentedon Sep 4, 2023
Also, just for my own sanity, I think we're now at the following migration script.
alialnu commentedon Sep 4, 2023
The UPDATE statement fails with:
I'm having a difficult time constructing a query to find the problematic IDs though.
stephenfin commentedon Sep 5, 2023
How about if we drop the subquery and do joins?
Again, disclaimer that this is not beyond validating that it's valid (MySQL) syntax.
alialnu commentedon Sep 5, 2023
Quick update while I try to rewrite the query:
Doesn't seem like it's valid syntax:
https://www.postgresql.org/docs/current/sql-update.html
stephenfin commentedon Sep 5, 2023
Guess that is MySQL only then. I was thinking as much but didn't want to go read the ANSI SQL docs (wherever they live) 😅
EDIT: StackOverflow suggests this might be the equivalent syntax?
?
alialnu commentedon Sep 27, 2023
Sorry for the late response @stephenfin, I missed your last suggestion.
The suggested query failed with:
I got it to work with these changes:
Removing duplicate patch comments still fails though: