[Toaster] RFC: upgrading to Django 1.8
Smith, Elliot
elliot.smith at intel.com
Mon Nov 16 11:08:28 PST 2015
I've been working on an upgrade of Toaster to Django 1.8.6 here:
poky-contrib, elliot/toaster/django_upgrade-8364
I've fixed all the deprecation warnings, fixed imports in a few places,
removed South, recreated the migrations etc., but the changes are fairly
minor.
However, the main issue I've found while doing this work is that with
Django 1.8 and SQLite, the Toaster database file is frequently locked,
meaning that either the back-end or front-end code is unable to access it.
This results in errors in one or other of the logs (toaster_web.log or
toaster_ui.log) and failures either to run a build or collect events from
it (if the back-end gets locked out) or failures to update the web UI
correctly (if the front-end gets locked out).
I did manage to get Toaster + MySQL working, though at the expense of
performance: I let Toaster autocommit each transaction for safety's sake by
removing all our manual transaction code
(de587e0d212b701f6592a39fa3ef5c411f2d9698). Without these changes, MySQL
gives errors about transactions being violated, presumably from the same
source which locks the SQLite database. But it generally copes OK, as it
can support a higher level of concurrency.
I've gone through the release notes for Django 1.7 and 1.8 (I'm upgrading
from 1.6) to try to identify any changes which might have caused this, but
nothing jumps out at me. I've attached my notes on this whole process.
The only thing I spotted which seems like a possible cause is this:
* "Management Commands"
"Database connections are now always closed after a management command
called from the command line has finished doing its job."
(from https://docs.djangoproject.com/en/1.8/releases/1.8/)
Toaster runs various Django management commands during setup/startup, and
also calls management commands from inside each other. I wonder whether
this might be causing the problem, as multiple commands in different
processes are attempting to lock the SQLite file so they can connect to the
db. (I'm still learning how SQLite does this stuff.)
To fix this, I may have to move the db logic from management commands into
a Django API running alongside toastergui. Our management commands would
invoke this API (via REST, maybe) and not write directly to the database
(as they do at the moment). This would allow Django to manage the database
connections, concurrency, transactions etc. and hopefully prevent SQLite
file locking. I think it would also provide a better architecture than what
we have now.
If anyone has any other ideas about what might cause adequate database code
in Django 1.6 to break entirely in 1.8 (with SQLite), please let me know.
Any comments or suggestions would be most welcome.
Elliot
--
Elliot Smith
Software Engineer
Intel Open Source Technology Centre
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.yoctoproject.org/pipermail/toaster/attachments/20151116/9dc05918/attachment-0001.html>
-------------- next part --------------
**********************************
DB LOCKING ISSUES IN DJANGO 1.8.6
Elliot Smith, 2015-11-16
I've been having issues with the SQLite database being locked when upgrading
Toaster to Django 1.8.6
This only occurs after upgrading to Django 1.8.6 (from 1.6): I wasn't
seeing these issues in Toaster master.
I started a new branch to do the upgrade to Django 1.8.6. Note that I
did this work on top of Ed's branch to merge the two modes; though, again,
I don't see any locking issues on Ed's branch.
The only changes I made are:
+ 561a1a355bd01fbddb959530e498695a60b50833 toaster: Upgrade to Django 1.8.6 and remove South
+ ac24da21cadeae8111e754da09654b75a3546da1 toaster: Modify startup script for new Django version and no South
+ a22e94632d8d51e529efb8c294591215b9cbde90 toaster: Remove South from INSTALLED_APPS
+ de00676fe49b90dafc662cba5c96e06f644ad18c toaster: Remove South migrations
+ 55a3c90923f519281e877abc6910a6a31bed8ff1 toaster: Replace migrations with Django ones
+ 88927e264b51a9d069b62ce6a8beb8c3e85efaee toaster: Create default project with get_or_create* method
+ 314f9793795acd96130e7644a78879e125709fcb toaster: Fix references to app paths
+ d3a4b9a69162dd7899e87938ece71b5148f4079a toaster: Remove compatible_layerversions() method
+ 356dc35bdafc00c7b284fcd6a153ecc794ce18af toaster: Start Django machinery for database access
+ 6cb11c93406ad3cefe574ab7cc799b8f89600037 toaster: Check Django version against toaster-requirements.txt
+ dd3ec25587d62cc4ea8e834a0d1e91eda532f5f5 toaster: Prevent deprecation warnings for RedirectView
+ 32f8a170723b343f57231e4e6203c9ba8ad7b702 toaster: Update API used to make runbuilds methods run in transactions
+ 8245e0fdd999de2ae9cd51f8188740e7be43c8a9 toaster: Update deprecated manage.py command
i.e. fixing deprecations sufficiently to allow the application to start; I didn't change any of the transaction code, except for replacing "commit_on_success" with "autocommit"; I may have modified how db connections are established inadvertantly, as I changed how our model code is imported into buildinfohelper
**********************************
SYMPTOMS
Testing with SQLite
Start toaster normally
Create a project
Try to use the "Build" form to start a new build
The database locks, either on the bitbake UI side, or on the Toaster side.
***
I sometimes get this in toaster_web.log:
2015-11-16 10:58:00,947 ERROR Internal Server Error: /toastergui/project/1/builds/
Traceback (most recent call last):
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/handlers/base.py", line 132, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/toastergui/views.py", line 166, in returned_wrapper
context = view(request, *args, **kwargs)
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/toastergui/views.py", line 2910, in projectbuilds
prj.schedule_build()
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/orm/models.py", line 288, in schedule_build
br.delete()
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/base.py", line 896, in delete
collector.delete()
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/deletion.py", line 309, in delete
query.delete_batch(pk_list, self.using)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/sql/subqueries.py", line 41, in delete_batch
self.do_query(self.get_meta().db_table, self.where, using=using)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/sql/subqueries.py", line 26, in do_query
self.get_compiler(using).execute_sql(NO_RESULTS)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 840, in execute_sql
cursor.execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/utils.py", line 98, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 318, in execute
return Database.Cursor.execute(self, query, params)
OperationalError: database is locked
And the build doesn't start
***
Or, alternatively, the build will try to start, and I'll get this in toaster_ui.log:
NOTE: Preparing RunQueue
ERROR: database is locked
Traceback (most recent call last):
File "/home/ell/dev/toaster/poky/bitbake/lib/bb/ui/toasterui.py", line 379, in main
buildinfohelper.store_dependency_information(event)
File "/home/ell/dev/toaster/poky/bitbake/lib/bb/ui/buildinfohelper.py", line 1288, in store_dependency_information
tasks[taskdesc] = _save_a_task(taskdesc)
File "/home/ell/dev/toaster/poky/bitbake/lib/bb/ui/buildinfohelper.py", line 1282, in _save_a_task
task_obj = self.orm_wrapper.get_update_task_object(task_info)
File "/home/ell/dev/toaster/poky/bitbake/lib/bb/ui/buildinfohelper.py", line 233, in get_update_task_object
task_name=task_information['task_name']
File "/home/ell/dev/toaster/poky/bitbake/lib/bb/ui/buildinfohelper.py", line 100, in _cached_get_or_create
clazz.objects.get_or_create(**kwargs)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/manager.py", line 127, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/query.py", line 407, in get_or_create
return self._create_object_from_params(lookup, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/query.py", line 439, in _create_object_from_params
obj = self.create(**params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/query.py", line 348, in create
obj.save(force_insert=True, using=self.db)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/base.py", line 734, in save
force_update=force_update, update_fields=update_fields)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/base.py", line 762, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/base.py", line 846, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/base.py", line 885, in _do_insert
using=using, raw=raw)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/manager.py", line 127, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/query.py", line 920, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 974, in execute_sql
cursor.execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/utils.py", line 98, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 318, in execute
return Database.Cursor.execute(self, query, params)
OperationalError: database is locked
**********************************
INVESTIGATION: runbuilds + runserver CAUSES THE ISSUE?
If I start Toaster then manually kill runbuilds, I don't get the locking issue in toaster_web.log (toaster_ui.log doesn't get populated, as runbuilds writes to this file, but the web UI doesn't).
If runserver is running on its own (though along with the bitbake server), the locking error doesn't occur.
This doesn't really help find the root cause, though, as runbuilds writes to the db; and the build triggered by runbuilds causes writes to the db as events are captured (by bitbake running with the toasterui UI).
**********************************
INVESTIGATION: toasterui IS THE PROBLEM, runbuilds IS OK?
Edit toasterui so it doesn't log any events from the triggered build; this then means that we just have runbuilds and runserver to worry about.
I edited toasterui.py, and did "return 0" from the main() function before it reaches the "while True:" loop.
In this situation, the build is added to the db and appears to be initiated; however, the events marking the progress of the build aren't picked up (obviously), so the build never terminates in Toaster.
This suggests that the issue is in buildinfohelper: as it writes to the db, it causes it to lock from the point of view of the front-end Toaster web UI, which causes the error in toaster_web.log; or, buildinfohelper is unable to write to the db as it registers events, as the web UI has locked it, which causes the error to appear in toaster_ui.log.
**********************************
INVESTIGATION: runbuilds LOCKS THE DB AND CAUSES buildinfohelper TO FAIL?
I modified runbuilds, removing "@transaction.autocommit" from the methods in that file.
However, I still got locking in the toaster UI back-end, which meant that the bitbake build failed; the web UI was still working correctly.
The error occurred in the call to buildinfohelper.store_dependency_information(), as follows:
ERROR: database is locked
Traceback (most recent call last):
File "/home/ell/dev/toaster/poky/bitbake/lib/bb/ui/toasterui.py", line 379, in main
buildinfohelper.store_dependency_information(event)
File "/home/ell/dev/toaster/poky/bitbake/lib/bb/ui/buildinfohelper.py", line 1288, in store_dependency_information
This suggests that runbuilds isn't to blame.
**********************************
INVESTIGATION: IS IT JUST SQLITE?
I configured Toaster to use MySQL:
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'toaster',
'USER': 'toaster',
'PASSWORD': 'toaster',
'HOST': '/opt/lampp/var/mysql/mysql.sock',
'PORT': ''
}
Then, when I tried to start Toaster, I got this error:
Failure while trying to import the toaster config file /home/ell/dev/toaster/poky/meta-yocto/conf/toasterconf.json: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
Traceback (most recent call last):
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py", line 114, in _verify_be
call_command("lsupdates")
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/management/__init__.py", line 120, in call_command
return command.execute(*args, **defaults)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/management/base.py", line 445, in execute
output = self.handle(*args, **options)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/management/base.py", line 661, in handle
return self.handle_noargs(**options)
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/orm/management/commands/lsupdates.py", line 12, in handle_noargs
ls.update()
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/orm/models.py", line 1017, in update
logger.debug("Failed saving recipe, ignoring: %s (%s:%s)" % (e, ro.layer_version, ri['filepath']+"/"+ri['filename']))
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/base.py", line 503, in __str__
return force_text(self).encode('utf-8')
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/utils/encoding.py", line 92, in force_text
s = six.text_type(s)
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/orm/models.py", line 1206, in __unicode__
return "%d %s (VCS %s, Project %s)" % (self.pk, str(self.layer), self.get_vcs_reference(), self.build.project if self.build is not None else "No project")
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/fields/related.py", line 604, in __get__
rel_obj = qs.get()
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/query.py", line 328, in get
num = len(clone)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/query.py", line 144, in __len__
self._fetch_all()
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/query.py", line 965, in _fetch_all
self._result_cache = list(self.iterator())
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/query.py", line 238, in iterator
results = compiler.execute_sql()
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 840, in execute_sql
cursor.execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/utils.py", line 59, in execute
self.db.validate_no_broken_transaction()
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/base/base.py", line 327, in validate_no_broken_transaction
"An error occurred in the current transaction. You can't "
TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
Traceback (most recent call last):
File "../bitbake/bin/../lib/toaster/manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/management/__init__.py", line 354, in execute_from_command_line
utility.execute()
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/management/__init__.py", line 346, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/management/base.py", line 394, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/management/base.py", line 445, in execute
output = self.handle(*args, **options)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/management/base.py", line 661, in handle
return self.handle_noargs(**options)
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py", line 158, in handle_noargs
retval += self._verify_default_settings()
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py", line 131, in _verify_default_settings
if ToasterSetting.objects.filter(name='DEFAULT_RELEASE').count() != 1:
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/query.py", line 318, in count
return self.query.get_count(using=self.db)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/sql/query.py", line 466, in get_count
number = obj.get_aggregation(using, ['__count'])['__count']
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/sql/query.py", line 447, in get_aggregation
result = compiler.execute_sql(SINGLE)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 840, in execute_sql
cursor.execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/utils.py", line 59, in execute
self.db.validate_no_broken_transaction()
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/base/base.py", line 327, in validate_no_broken_transaction
"An error occurred in the current transaction. You can't "
django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
Note that this was triggered from lsupdates. This hints that the issue might be to do with how management commands on the command-line now occur inside transactions (they didn't before); and that these transactions could be causing the db to lock when queries are being simultaneously run against it.
Because queries aren't inside transactions, they are blocked if they occur when a transaction is active.
Also, because our management commands call other management commands, their transactions appear to be interfering with each other. When I attempted to wrap parts of our commands with:
with transaction.atomic():
...
I saw errors like:
Failure while trying to import the toaster config file /home/ell/dev/toaster/poky/meta-yocto/conf/toasterconf.json: This is forbidden when an 'atomic' block is active.
Traceback (most recent call last):
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py", line 118, in _verify_be
call_command("lsupdates")
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/management/__init__.py", line 120, in call_command
return command.execute(*args, **defaults)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/management/base.py", line 445, in execute
output = self.handle(*args, **options)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/core/management/base.py", line 661, in handle
return self.handle_noargs(**options)
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/orm/management/commands/lsupdates.py", line 13, in handle_noargs
ls.update()
File "/home/ell/dev/toaster/poky/bitbake/lib/toaster/orm/models.py", line 889, in update
transaction.set_autocommit(False)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/transaction.py", line 35, in set_autocommit
return get_connection(using).set_autocommit(autocommit)
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/base/base.py", line 293, in set_autocommit
self.validate_no_atomic_block()
File "/home/ell/toaster-run/toaster-env/lib/python2.7/site-packages/django/db/backends/base/base.py", line 322, in validate_no_atomic_block
"This is forbidden when an 'atomic' block is active.")
TransactionManagementError: This is forbidden when an 'atomic' block is active.
**********************************
INVESTIGATION: MAYBE IF I TURN OUR TRANSACTION SPAGHETTI OFF...?
Toaster has lots of transaction code sprinkled as if at random through it. It typically takes this form:
if not connection.features.autocommits_when_autocommit_is_off:
transaction.set_autocommit(False)
and the inverse of this to turn autocommit transactions back on.
The problem with this is that it can cause issues with MySQL, which uses autocommit to wrap interactions with the database. Because Django is trying to create transactions, but we're then riding roughshod over that, we get the conflicts seen above.
It might be sensible to just remove all of this code, and let the database handle the transactions itself. While this might cause a performance hit, it may help to move towards a more performant solution over time.
(I don't think this is what's causing the database locking, but it is preventing MySQL from working correctly.)
It may also be necessary to wrap db interactions occurring in management command code so that it uses transactions, too. (Though autocommit should be turned on by default anyway, so just removing our manual transaction management may fix this, and mean that we don't need to create our own explicit transactions.)
Setting "ATOMIC_REQUESTS": True for the database in settings.py might also help; though, again, removing all of our manual transaction management may be enough.
**********************************
SOLUTION 1: REMOVE MANUAL TRANSACTIONS
Removing all of the autocommit on/off code meant that the layer index could be imported into MySQL, and that Toaster ran properly without throwing errors, capable of building recipes etc.
I didn't need to do any extra wrapping of management code, or set "ATOMIC_REQUESTS":True, as the solution worked without these.
However, performance was not great, and the initial import of the data took a long, long time.
And, I still got "database is locked" errors with SQLite.
Setting ATOMIC_REQUESTS:True doesn't help in the case of SQLite, either.
**********************************
DJANGO UPGRADE NOTES 1.8
(https://docs.djangoproject.com/en/1.8/releases/1.8/)
Django changes which might have a bearing on these issues:
* "Database connections are considered equal only if they’re the same object. They aren’t hashable any more."
(maybe runbuilds and runserver used to share a connection? could this be related to the fact that I changed how imports work in buildinfohelper, so I'm no longer importing "preloaded" versions of modules [i.e. modules which had been loaded by runserver and set up with a db connection before runbuilds started]? were we sharing db connections previously without realising?)
* "Related object operations are run in a transaction
"Some operations on related objects such as add() or direct assignment ran multiple data modifying queries without wrapping them in transactions. To reduce the risk of data corruption, all data modifying methods that affect multiple related objects (i.e. add(), remove(), clear(), and direct assignment) now perform their data modifying queries from within a transaction, provided your database supports transactions."
(are transactions happening automatically in places where they didn't before, causing the db to lock at a point where it wasn't locking previously?)
* "Management Commands
"Database connections are now always closed after a management command called from the command line has finished doing its job."
(are we locking the db with our call to runbuilds, which is a management command which we are invoking from the command-line?)
* "The following transaction management APIs are removed:
"the decorators and context managers autocommit, commit_on_success, and commit_manually, defined in django.db.transaction"
(I had to modify two references to commit_on_success in runbuilds.py to autocommit, as the commit_on_success API is deprecated; could this have caused a problem?)
**********************************
DJANGO UPGRADE NOTES 1.7
(https://docs.djangoproject.com/en/1.8/releases/1.7/)
Django changes which might have a bearing on these issues:
* "Using database cursors as context managers"
(I don't think this would have an effect)
* "The remove() and clear() methods of the related managers created by ForeignKey, GenericForeignKey, and ManyToManyField suffered from a number of issues. Some operations ran multiple data modifying queries without wrapping them in a transaction, and some operations didn’t respect default filtering when it was present (i.e. when the default manager on the related model implemented a custom get_queryset())."
(this implies that these operations are now wrapped in transactions; could this have caused a locking issue?)
* "select_for_update() requires a transaction¶
"Historically, queries that use select_for_update() could be executed in autocommit mode, outside of a transaction. Before Django 1.6, Django’s automatic transactions mode allowed this to be used to lock records until the next write operation. Django 1.6 introduced database-level autocommit; since then, execution in such a context voids the effect of select_for_update(). It is, therefore, assumed now to be an error and raises an exception."
(we use select_for_update in a couple of places, but I don't think the places where it is being used are active when I see the locking behaviour)
More information about the toaster
mailing list