Open knazarov opened 3 years ago
Usage scenario:
local transaction_id = crud.transaction_begin({timeout=10}) -- seconds
local user = crud.get('user', 1)
local amount = 100
local saving = crud.select('account',
{{'=', 'user_id', user.id}, {'=', 'account_type', 'saving'}},
{transaction=transaction_id})
if saving.amount > amount then
saving.amount = saving.amount - amount
crud.replace('account', saving, {transaction=transaction_id})
local primary = crud.select('account',
{{'=', 'user_id', user.id}, {'=', 'account_type', 'primary'}},
{transaction=transaction_id})
primary.amount = primary.amount + amount
crud.replace('account', primary, {transaction=transaction_id})
crud.transaction_commit(transaction_id)
else
crud.transaction_abort(transaction_id)
log.error('Insufficient funds on saving account for user %s', user.name)
end
This approach will also map quite well onto GraphQL in Data Grid.
Interactive transactions have made it into the core recently.
Just note: https://github.com/tarantool/tarantool/issues/4897 is done (we consider it as beta now), https://github.com/tarantool/tarantool/issues/2016 is not.
@Totktonada for crud
we don’t need support from iproto.
This is how to use interactive transactions
#!/usr/bin/env tarantool
local fiber = require('fiber')
-- If you just use box.cfg{}, this app will fail
box.cfg{memtx_use_mvcc_engine=true}
--box.cfg{}
box.schema.space.create('account', {if_not_exists=true})
box.space.account:format({ {name='id',type='unsigned'},
{name='first_name',type='string'},
{name='last_name',type='string'},
})
box.begin()
box.space.account:put({2, "John", "Doe"})
print("sleeping")
fiber.sleep(1)
print("woke up")
box.space.account:put({3, "Ivan", "Ivanov"})
box.commit()
os.exit(0)
Interactive transactions have made it into the core recently. They allow us to open a transaction and do selects/updates with yield. I suggest that we add support for them to
crud
.Unfortunately, we won't get multi-node transactions, but since we have an understanding of which shard the operation will go to, we can still allow transactional operations if they touch only one storage.
This should be pretty easy to implement: if we open a transaction, record which node the first operation goes to, then make sure all other operations in the transaction go to the same node. If not, abort the operation or the whole transaction.