diff mbox

migrations: Optimize 0007 patch comment for psql

Message ID 1458248656-3342-1-git-send-email-andy.doan@linaro.org
State Superseded
Headers show

Commit Message

Andy Doan March 17, 2016, 9:04 p.m. UTC
By handling comment copying/deletion via SQL we can make migration take
<3 minutes rather than >30minutes for big instances. The SQL is vendor
specific, so a similar query would need to be added to support MySQL.

Signed-off-by: Andy Doan <andy.doan@linaro.org>
---
 .../0007_move_comment_content_to_patch_content.py  | 89 +++++++++++++---------
 1 file changed, 51 insertions(+), 38 deletions(-)

Comments

Stephen Finucane March 21, 2016, 6:23 p.m. UTC | #1
On 17 Mar 16:04, Andy Doan wrote:
> By handling comment copying/deletion via SQL we can make migration take
> <3 minutes rather than >30minutes for big instances. The SQL is vendor
> specific, so a similar query would need to be added to support MySQL.
> 
> Signed-off-by: Andy Doan <andy.doan@linaro.org>

Nice. I'll review this (and the REST API proposal) tomorrow morning!

Stephen
Stephen Finucane March 23, 2016, 5:01 p.m. UTC | #2
On 17 Mar 16:04, Andy Doan wrote:
> By handling comment copying/deletion via SQL we can make migration take
> <3 minutes rather than >30minutes for big instances. The SQL is vendor
> specific, so a similar query would need to be added to support MySQL.
> 
> Signed-off-by: Andy Doan <andy.doan@linaro.org>

Some nits below, but nothing important so happy to merge. Any chance
you want to do the same for MySQL? :)

Reviewed-by: Stephen Finucane <stephen.finucane@intel.com>

Stephen

> ---
>  .../0007_move_comment_content_to_patch_content.py  | 89 +++++++++++++---------
>  1 file changed, 51 insertions(+), 38 deletions(-)
> 
> diff --git a/patchwork/migrations/0007_move_comment_content_to_patch_content.py b/patchwork/migrations/0007_move_comment_content_to_patch_content.py
> index 63d57ba..aea65fe 100644
> --- a/patchwork/migrations/0007_move_comment_content_to_patch_content.py
> +++ b/patchwork/migrations/0007_move_comment_content_to_patch_content.py
> @@ -1,47 +1,60 @@
>  # -*- coding: utf-8 -*-
>  from __future__ import unicode_literals
>  
> -from django.db import migrations
> -
> -
> -def copy_comment_field(apps, schema_editor):
> -    Comment = apps.get_model('patchwork', 'Comment')
> -    Patch = apps.get_model('patchwork', 'Patch')
> -
> -    for patch in Patch.objects.all():
> -        try:
> -            # when available, this can only return one entry due to the
> -            # unique_together constraint
> -            comment = Comment.objects.get(patch=patch, msgid=patch.msgid)
> -        except Comment.DoesNotExist:
> -            # though there's no requirement to actually have a comment
> -            continue
> -
> -        patch.content = comment.content
> -        patch.save()
> +from django.db import connection, migrations
> +
> +if connection.vendor == 'postgresql'

I'd rather this check be done in each function, rather than having multiple
functions. It just seems...cleaner.

> +    def copy_comment_field(apps, schema_editor):
> +        schema_editor.execute('''
> +            UPDATE patchwork_patch
> +              SET content = patchwork_comment.content
> +            FROM patchwork_comment
> +              WHERE patchwork_patch.id=patchwork_comment.patch_id
> +                    AND patchwork_patch.msgid=patchwork_comment.msgid
> +        ''')
> +
> +    def remove_duplicate_comments(apps, schema_editor):
> +        schema_editor.execute('''
> +            DELETE FROM patchwork_comment
> +              USING patchwork_patch
> +              WHERE patchwork_patch.id=patchwork_comment.patch_id
> +                    AND patchwork_patch.msgid=patchwork_comment.msgid
> +        ''')
> +else:
> +    def copy_comment_field(apps, schema_editor):
> +        Comment = apps.get_model('patchwork', 'Comment')
> +        Patch = apps.get_model('patchwork', 'Patch')
> +
> +        for patch in Patch.objects.all():
> +            try:
> +                # when available, this can only return one entry due to the
> +                # unique_together constraint
> +                comment = Comment.objects.get(patch=patch, msgid=patch.msgid)
> +            except Comment.DoesNotExist:
> +                # though there's no requirement to actually have a comment
> +                continue
> +
> +            patch.content = comment.content
> +            patch.save()
> +
> +    def remove_duplicate_comments(apps, schema_editor):
> +        Comment = apps.get_model('patchwork', 'Comment')
> +        Patch = apps.get_model('patchwork', 'Patch')
> +
> +        for patch in Patch.objects.all():
> +            try:
> +                # when available, this can only return one entry due to the
> +                # unique_together constraint
> +                comment = Comment.objects.get(patch=patch, msgid=patch.msgid)
> +                comment.delete()
> +            except Comment.DoesNotExist:
> +                # though there's no requirement to actually have a comment
> +                continue
>  
>  
>  def uncopy_comment_field(apps, schema_editor):
> -    Patch = apps.get_model('patchwork', 'Patch')
> -
> -    for patch in Patch.objects.all():
> -        patch.content = None
> -        patch.save()
> -
> -
> -def remove_duplicate_comments(apps, schema_editor):
> -    Comment = apps.get_model('patchwork', 'Comment')
> -    Patch = apps.get_model('patchwork', 'Patch')
> -
> -    for patch in Patch.objects.all():
> -        try:
> -            # when available, this can only return one entry due to the
> -            # unique_together constraint
> -            comment = Comment.objects.get(patch=patch, msgid=patch.msgid)
> -            comment.delete()
> -        except Comment.DoesNotExist:
> -            # though there's no requirement to actually have a comment
> -            continue
> +    # This is no-op because the column is being deleted
> +    pass
>  
>  
>  def recreate_comments(apps, schema_editor):

Is it possible to migrate this also? Is it worth it?

Stephen
Andy Doan March 24, 2016, 1:52 p.m. UTC | #3
On 03/23/2016 12:01 PM, Finucane, Stephen wrote:
> On 17 Mar 16:04, Andy Doan wrote:
>> By handling comment copying/deletion via SQL we can make migration take
>> <3 minutes rather than >30minutes for big instances. The SQL is vendor
>> specific, so a similar query would need to be added to support MySQL.
>>
>> Signed-off-by: Andy Doan <andy.doan@linaro.org>
>
> Some nits below, but nothing important so happy to merge. Any chance
> you want to do the same for MySQL? :)

I'll give it a shot.


> I'd rather this check be done in each function, rather than having multiple
> functions. It just seems...cleaner.

will do

>>   def recreate_comments(apps, schema_editor):
>
> Is it possible to migrate this also? Is it worth it?

I'm sure someone with more DB experience would have a trick, but given 
its only for a reverse migration I figured it wasn't worth it.
Stephen Finucane March 24, 2016, 3:50 p.m. UTC | #4
On 24 Mar 08:52, Andy Doan wrote:
> On 03/23/2016 12:01 PM, Finucane, Stephen wrote:
> >On 17 Mar 16:04, Andy Doan wrote:
> >>By handling comment copying/deletion via SQL we can make migration take
> >><3 minutes rather than >30minutes for big instances. The SQL is vendor
> >>specific, so a similar query would need to be added to support MySQL.
> >>
> >>Signed-off-by: Andy Doan <andy.doan@linaro.org>
> >
> >Some nits below, but nothing important so happy to merge. Any chance
> >you want to do the same for MySQL? :)
> 
> I'll give it a shot.

No panic. This can be a separate follow-up patch to get this through.

> >I'd rather this check be done in each function, rather than having multiple
> >functions. It just seems...cleaner.
> 
> will do
> 
> >>  def recreate_comments(apps, schema_editor):
> >
> >Is it possible to migrate this also? Is it worth it?
> 
> I'm sure someone with more DB experience would have a trick, but
> given its only for a reverse migration I figured it wasn't worth it.

Makes sense.
diff mbox

Patch

diff --git a/patchwork/migrations/0007_move_comment_content_to_patch_content.py b/patchwork/migrations/0007_move_comment_content_to_patch_content.py
index 63d57ba..aea65fe 100644
--- a/patchwork/migrations/0007_move_comment_content_to_patch_content.py
+++ b/patchwork/migrations/0007_move_comment_content_to_patch_content.py
@@ -1,47 +1,60 @@ 
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 
-from django.db import migrations
-
-
-def copy_comment_field(apps, schema_editor):
-    Comment = apps.get_model('patchwork', 'Comment')
-    Patch = apps.get_model('patchwork', 'Patch')
-
-    for patch in Patch.objects.all():
-        try:
-            # when available, this can only return one entry due to the
-            # unique_together constraint
-            comment = Comment.objects.get(patch=patch, msgid=patch.msgid)
-        except Comment.DoesNotExist:
-            # though there's no requirement to actually have a comment
-            continue
-
-        patch.content = comment.content
-        patch.save()
+from django.db import connection, migrations
+
+if connection.vendor == 'postgresql':
+    def copy_comment_field(apps, schema_editor):
+        schema_editor.execute('''
+            UPDATE patchwork_patch
+              SET content = patchwork_comment.content
+            FROM patchwork_comment
+              WHERE patchwork_patch.id=patchwork_comment.patch_id
+                    AND patchwork_patch.msgid=patchwork_comment.msgid
+        ''')
+
+    def remove_duplicate_comments(apps, schema_editor):
+        schema_editor.execute('''
+            DELETE FROM patchwork_comment
+              USING patchwork_patch
+              WHERE patchwork_patch.id=patchwork_comment.patch_id
+                    AND patchwork_patch.msgid=patchwork_comment.msgid
+        ''')
+else:
+    def copy_comment_field(apps, schema_editor):
+        Comment = apps.get_model('patchwork', 'Comment')
+        Patch = apps.get_model('patchwork', 'Patch')
+
+        for patch in Patch.objects.all():
+            try:
+                # when available, this can only return one entry due to the
+                # unique_together constraint
+                comment = Comment.objects.get(patch=patch, msgid=patch.msgid)
+            except Comment.DoesNotExist:
+                # though there's no requirement to actually have a comment
+                continue
+
+            patch.content = comment.content
+            patch.save()
+
+    def remove_duplicate_comments(apps, schema_editor):
+        Comment = apps.get_model('patchwork', 'Comment')
+        Patch = apps.get_model('patchwork', 'Patch')
+
+        for patch in Patch.objects.all():
+            try:
+                # when available, this can only return one entry due to the
+                # unique_together constraint
+                comment = Comment.objects.get(patch=patch, msgid=patch.msgid)
+                comment.delete()
+            except Comment.DoesNotExist:
+                # though there's no requirement to actually have a comment
+                continue
 
 
 def uncopy_comment_field(apps, schema_editor):
-    Patch = apps.get_model('patchwork', 'Patch')
-
-    for patch in Patch.objects.all():
-        patch.content = None
-        patch.save()
-
-
-def remove_duplicate_comments(apps, schema_editor):
-    Comment = apps.get_model('patchwork', 'Comment')
-    Patch = apps.get_model('patchwork', 'Patch')
-
-    for patch in Patch.objects.all():
-        try:
-            # when available, this can only return one entry due to the
-            # unique_together constraint
-            comment = Comment.objects.get(patch=patch, msgid=patch.msgid)
-            comment.delete()
-        except Comment.DoesNotExist:
-            # though there's no requirement to actually have a comment
-            continue
+    # This is no-op because the column is being deleted
+    pass
 
 
 def recreate_comments(apps, schema_editor):