瀏覽代碼

HUE-4631 [home] DB transaction failing because of atomic block on home page

Jenny Kim 9 年之前
父節點
當前提交
bedc719
共有 3 個文件被更改,包括 120 次插入106 次删除
  1. 23 20
      desktop/core/src/desktop/configuration/api.py
  2. 28 23
      desktop/core/src/desktop/converters.py
  3. 69 63
      desktop/core/src/desktop/models.py

+ 23 - 20
desktop/core/src/desktop/configuration/api.py

@@ -199,28 +199,31 @@ def _update_default_and_group_configurations(configurations):
   :param configurations: Dictionary of app to configuration objects. Only processes "default" and "groups" configs
   :return: updated configurations dict
   """
-  with transaction.atomic():
-    # delete all previous default and group configurations
-    DefaultConfiguration.objects.filter(Q(is_default=True) | Q(groups__isnull=False)).delete()
-
-    for app, configs in configurations.items():
-      if 'default' in configs:
-        properties = configs['default']
-        if properties:
-          _save_configuration(app, properties, is_default=True)
-          LOG.info('Saved default configuration for app: %s' % app)
-
-      if 'groups' in configs:
-        for group_config in configs['groups']:
-          group_ids = group_config.get('group_ids')
-          properties = group_config.get('properties')
+  try:
+    with transaction.atomic():
+      # delete all previous default and group configurations
+      DefaultConfiguration.objects.filter(Q(is_default=True) | Q(groups__isnull=False)).delete()
 
+      for app, configs in configurations.items():
+        if 'default' in configs:
+          properties = configs['default']
           if properties:
-            try:
-              groups = Group.objects.filter(id__in=group_ids)
-              _save_configuration(app, properties, is_default=False, groups=groups)
-            except Group.DoesNotExist, e:
-              raise PopupException(_('Could not find one or more groups with IDs: %s') % ', '.join(group_ids))
+            _save_configuration(app, properties, is_default=True)
+            LOG.info('Saved default configuration for app: %s' % app)
+
+        if 'groups' in configs:
+          for group_config in configs['groups']:
+            group_ids = group_config.get('group_ids')
+            properties = group_config.get('properties')
+
+            if properties:
+              try:
+                groups = Group.objects.filter(id__in=group_ids)
+                _save_configuration(app, properties, is_default=False, groups=groups)
+              except Group.DoesNotExist, e:
+                raise PopupException(_('Could not find one or more groups with IDs: %s') % ', '.join(group_ids))
+  except Exception, e:
+    raise PopupException(_('Failed to update configurations: %s') % e)
 
   return _get_default_configurations()
 

+ 28 - 23
desktop/core/src/desktop/converters.py

@@ -20,7 +20,9 @@ import logging
 import time
 
 from django.db import transaction
+from django.utils.translation import ugettext as _
 
+from desktop.lib.exceptions_renderable import PopupException
 from desktop.models import Document, DocumentPermission, DocumentTag, Document2, Directory, Document2Permission
 from notebook.api import _historify
 from notebook.models import import_saved_beeswax_query
@@ -198,26 +200,29 @@ class DocumentConverter(object):
 
 
   def _create_doc2(self, document, doctype, name=None, description=None, data=None):
-    with transaction.atomic():
-      document2 = Document2.objects.create(
-        owner=self.user,
-        parent_directory=self._get_parent_directory(document),
-        name=name if name else document.name,
-        type=doctype,
-        description=description,
-        data=data
-      )
-      self._sync_permissions(document, document2)
-
-      # Create a doc1 copy and link it for backwards compatibility
-      Document.objects.link(
-        document2,
-        owner=document2.owner,
-        name=document2.name,
-        description=document2.description,
-        extra=document.extra
-      )
-
-      document.add_tag(self.imported_tag)
-      document.save()
-      return document2
+    try:
+      with transaction.atomic():
+        document2 = Document2.objects.create(
+          owner=self.user,
+          parent_directory=self._get_parent_directory(document),
+          name=name if name else document.name,
+          type=doctype,
+          description=description,
+          data=data
+        )
+        self._sync_permissions(document, document2)
+
+        # Create a doc1 copy and link it for backwards compatibility
+        Document.objects.link(
+          document2,
+          owner=document2.owner,
+          name=document2.name,
+          description=document2.description,
+          extra=document.extra
+        )
+
+        document.add_tag(self.imported_tag)
+        document.save()
+        return document2
+    except Exception, e:
+      raise PopupException(_("Failed to convert Document object: %s") % e)

+ 69 - 63
desktop/core/src/desktop/models.py

@@ -509,64 +509,67 @@ class DocumentManager(models.Manager):
       LOG.info('Looking for documents that have no object')
 
       # Delete documents with no object.
-      with transaction.atomic():
-        # First, delete all the documents that don't have a content type
-        docs = Document.objects.filter(content_type=None)
-
-        if docs:
-          LOG.info('Deleting %s doc(s) that do not have a content type' % docs.count())
-          docs.delete()
-
-        # Next, it's possible that there are documents pointing at a non-existing
-        # content_type. We need to do a left join to find these records, but we
-        # can't do this directly in django. To get around writing wrap sql (which
-        # might not be portable), we'll use an aggregate to count up all the
-        # associated content_types, and delete the documents that have a count of
-        # zero.
-        #
-        # Note we're counting `content_type__name` to force the join.
-        docs = Document.objects \
-            .values('id') \
-            .annotate(content_type_count=models.Count('content_type__name')) \
-            .filter(content_type_count=0)
-
-        if docs:
-          LOG.info('Deleting %s doc(s) that have invalid content types' % docs.count())
-          docs.delete()
-
-        # Finally we need to delete documents with no associated content object.
-        # This is tricky because of our use of generic foreign keys. So to do
-        # this a bit more efficiently, we'll start with a query of all the
-        # documents, then step through each content type and and filter out all
-        # the documents it's referencing from our document query. Messy, but it
-        # works.
-
-        docs = Document.objects.all()
-
-        for content_type in ContentType.objects.all():
-          model_class = content_type.model_class()
-
-          # Ignore any types that don't have a model.
-          if model_class is None:
-            continue
-
-          # Ignore types that don't have a table yet.
-          if model_class._meta.db_table not in table_names:
-            continue
-
-          # Ignore classes that don't have a 'doc'.
-          if not hasattr(model_class, 'doc'):
-            continue
-
-          # First create a query that grabs all the document ids for this type.
-          docs_from_content = model_class.objects.values('doc__id')
-
-          # Next, filter these from our document query.
-          docs = docs.exclude(id__in=docs_from_content)
-
-        if docs.exists():
-          LOG.info('Deleting %s documents' % docs.count())
-          docs.delete()
+      try:
+        with transaction.atomic():
+          # First, delete all the documents that don't have a content type
+          docs = Document.objects.filter(content_type=None)
+
+          if docs:
+            LOG.info('Deleting %s doc(s) that do not have a content type' % docs.count())
+            docs.delete()
+
+          # Next, it's possible that there are documents pointing at a non-existing
+          # content_type. We need to do a left join to find these records, but we
+          # can't do this directly in django. To get around writing wrap sql (which
+          # might not be portable), we'll use an aggregate to count up all the
+          # associated content_types, and delete the documents that have a count of
+          # zero.
+          #
+          # Note we're counting `content_type__name` to force the join.
+          docs = Document.objects \
+              .values('id') \
+              .annotate(content_type_count=models.Count('content_type__name')) \
+              .filter(content_type_count=0)
+
+          if docs:
+            LOG.info('Deleting %s doc(s) that have invalid content types' % docs.count())
+            docs.delete()
+
+          # Finally we need to delete documents with no associated content object.
+          # This is tricky because of our use of generic foreign keys. So to do
+          # this a bit more efficiently, we'll start with a query of all the
+          # documents, then step through each content type and and filter out all
+          # the documents it's referencing from our document query. Messy, but it
+          # works.
+
+          docs = Document.objects.all()
+
+          for content_type in ContentType.objects.all():
+            model_class = content_type.model_class()
+
+            # Ignore any types that don't have a model.
+            if model_class is None:
+              continue
+
+            # Ignore types that don't have a table yet.
+            if model_class._meta.db_table not in table_names:
+              continue
+
+            # Ignore classes that don't have a 'doc'.
+            if not hasattr(model_class, 'doc'):
+              continue
+
+            # First create a query that grabs all the document ids for this type.
+            docs_from_content = model_class.objects.values('doc__id')
+
+            # Next, filter these from our document query.
+            docs = docs.exclude(id__in=docs_from_content)
+
+          if docs.exists():
+            LOG.info('Deleting %s documents' % docs.count())
+            docs.delete()
+      except Exception, e:
+        LOG.exception('Error in sync while attempting to delete documents with no object: %s' % e)
 
 
 class Document(models.Model):
@@ -1250,11 +1253,14 @@ class Document2(models.Model):
       return None
 
   def share(self, user, name='read', users=None, groups=None):
-    with transaction.atomic():
-      self.update_permission(user, name, users, groups)
-      # For directories, update all children recursively with same permissions
-      for child in self.children.all():
-        child.share(user, name, users, groups)
+    try:
+      with transaction.atomic():
+        self.update_permission(user, name, users, groups)
+        # For directories, update all children recursively with same permissions
+        for child in self.children.all():
+          child.share(user, name, users, groups)
+    except Exception, e:
+      raise PopupException(_("Failed to share document: %s") % e)
     return self
 
   def update_permission(self, user, name='read', users=None, groups=None):