ddl: allow to execute non-yielding DDL statements in transactions
The patch is pretty straightforward - all it does is moves checks for single statement transactions from alter.cc to txn_enable_yield_for_ddl so that now any DDL request may be executed in a transaction unless it builds an index or checks the format of a non-empty space (those are the only two operations that may yield). There's two things that must be noted explicitly. The first is removal of an assertion from priv_grant. The assertion ensured that a revoked privilege was in the cache. The problem is the cache is built from the contents of the space, see user_reload_privs. On rollback, we first revert the content of the space to the original state, and only then start invoking rollback triggers, which call priv_grant. As a result, we will revert the cache to the original state right after the first trigger is invoked and the following triggers will have no effect on it. Thus we have to remove this assertion. The second subtlety lays in vinyl_index_commit_modify. Before the commit we assumed that if statement lsn is <= vy_lsm::commit_lsn, then it must be local recovery from WAL. Now it's not true, because there may be several operations for the same index in a transaction, and they all will receive the same signature in on_commit trigger. We could, of course, try to assign different signatures to them, but that would look cumbersome - better simply allow lsn <= vy_lsm::commit_lsn after local recovery, there's actually nothing wrong about that. Closes #4083 @TarantoolBot document Title: Transactional DDL Now it's possible to group non-yielding DDL statements into transactions, e.g. ```Lua box.begin() box.schema.space.create('my_space') box.space.my_space:create_index('primary') box.commit() -- or box.rollback() ``` Most DDL statements don't yield and hence can be run from transactions. There are just two exceptions: creation of a new index and changing the format of a non-empty space. Those are long operations that may yield so as not to block the event loop for too long. Those statements can't be executed from transactions (to be more exact, such a statement must go first in any transaction). Also, just like in case of DML transactions in memtx, it's forbidden to explicitly yield in a DDL transaction by calling fiber.sleep or any other yielding function. If this happens, the transaction will be aborted and an attempt to commit it will fail.
Showing
- src/box/alter.cc 0 additions, 14 deletionssrc/box/alter.cc
- src/box/errcode.h 1 addition, 1 deletionsrc/box/errcode.h
- src/box/memtx_space.c 8 additions, 0 deletionssrc/box/memtx_space.c
- src/box/txn.c 1 addition, 2 deletionssrc/box/txn.c
- src/box/txn.h 5 additions, 12 deletionssrc/box/txn.h
- src/box/user.cc 0 additions, 1 deletionsrc/box/user.cc
- src/box/vinyl.c 18 additions, 5 deletionssrc/box/vinyl.c
- test/box/misc.result 1 addition, 0 deletionstest/box/misc.result
- test/box/on_replace.result 25 additions, 28 deletionstest/box/on_replace.result
- test/box/on_replace.test.lua 5 additions, 8 deletionstest/box/on_replace.test.lua
- test/box/transaction.result 61 additions, 21 deletionstest/box/transaction.result
- test/box/transaction.test.lua 45 additions, 11 deletionstest/box/transaction.test.lua
- test/engine/ddl.result 56 additions, 2 deletionstest/engine/ddl.result
- test/engine/ddl.test.lua 37 additions, 2 deletionstest/engine/ddl.test.lua
Loading
Please register or sign in to comment