Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move transaction.atomic contexts to lower level #5790

Closed
wants to merge 1 commit into from
Closed

move transaction.atomic contexts to lower level #5790

wants to merge 1 commit into from

Conversation

bartosh
Copy link

@bartosh bartosh commented Dec 8, 2015

Wrapping 'execute_sql' into transaction.atomic instead of
wrapping 'create' and 'save' should increase parallelism and
spead up execution of 'insert' and 'update' SQL queries.

@@ -495,8 +494,7 @@ def _create_object_from_params(self, lookup, params):
Used by get_or_create and update_or_create
"""
try:
with transaction.atomic(using=self.db):
obj = self.create(**params)
obj = self.create(**params)
return obj, True
except IntegrityError:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes makes it not obvious at all that the contents of the try/except IntegrityError are properly wrapped in a transaction.

This is necessary to prevent errors on databases which actually enforce transactional integrity on errors like PostgreSQL.

@aaugustin
Copy link
Member

It's unclear to me that this change preserves transactional integrity of changes in cases of concrete inheritance.

@bartosh
Copy link
Author

bartosh commented Dec 8, 2015

My understanding was that save or create calls will anyway end up calling _insert _update or update down the stack. So moving atomic context there should make execution of queries go more smoothly by avoiding wrapping extra code into transaction.atomic.

Does it make sense for you?

@aaugustin
Copy link
Member

What if a single call to save() triggers multiple calls to _insert? This happens with concrete inheritance.

There is no need to wrap calls of create and save methods in
transaction.atomic as it's already done down the call stack in
Model.save_base method.
@bartosh
Copy link
Author

bartosh commented Dec 9, 2015

The case you've mentioned is taken care by this code in Model.save_base:
with transaction.atomic(using=using, savepoint=False):
if not raw:
self._save_parents(cls, using, update_fields)
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)

@akaariai
Copy link
Member

akaariai commented Dec 9, 2015

I don't think this PR is correct at all. transaction.atomic() is removed from a couple of places where save() or create() is called, and then transaction.atomic() is added to all _insert/_create operations.

Also, the claim that this increases parallelism and performance isn't backed up by any data, and I don't see any obvious reason why this would be so.

@bartosh
Copy link
Author

bartosh commented Dec 9, 2015

Fair enough. Closing this PR. will send another one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants