What would you say about checking which CRUD operations were executed within atomic() call (in order to serialize them and save into a special model for databases which don't support this functionality) ? Is it realistic?
What I mean by that is that when you do:
from django.db import transaction
with transaction.atomic():
MyModel.objects.create(field=123)
then the generated SQL is something like
BEGIN;
INSERT INTO mymodel values (123);
COMMIT;
However, if the database doesn't support the TPC functionality, the SQL would have to be slightly different, say:
BEGIN;
INSERT INTO prepared_transactions (txn_id, model, operation, params) values ('foo', 'MyModel', 'create', '{field:123}');
COMMIT;
But on the other hand, if the database does support that, it could be 'normal', i.e.:
BEGIN;
INSERT INTO mymodel values ( ... )
BEGIN TRANSACTION 'foo';
(no COMMIT)
If it is not possible to trace the CRUD operations, would it be easier to introduce a slightly different syntax, say ...
from django.db import prepare_distributed:
with prepare_distributed('foo') as prepare:
prepare.add_operation(MyModel.objects.create, {'field': 123})
After all, it's not like the developer doesn't know whether he's doing a distributed transaction or not..
As for making the atomic() more complex, I don't think that it would be significantly hard. The distributed transaction isn't really *that* different - it's just calling PREPARE TRANSACTION 'foo' (without calling COMMIT). I thought that the Atomic class could simply have some kind of inner method hooks. The default class could then implement those:
class Atomic(ContextDecorator):
def _commit_wrapper(self, connection):
return connection.commit()
but the Two phase could do it differently:
class TwoPhaseAtomic(Atomic):
def _commit_wrapper(self, connection):
return connection.prepare_distributed(self.distributed_transaction_id);
Of course, the prepare_distributed call would create models in the special table if the database wouldn't support the functionality and call regular commit() at the end, or call appropriate command otherwise - so this seems like the easiest thing to do. The problem that I haven't figured out yet would be to trace the instances being saved / created / etc ..