diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 0041286b63932a3d8fb0bd50940ace2fdb528b59..88c912f6cc18c5a5c3d8d077a475f5da779c4216 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -228,6 +228,21 @@ box.begin = function() box.error() end end + +local function atomic_tail(status, ...) + if not status then + box.rollback() + error((...), 2) + end + box.commit() + return ... +end + +box.atomic = function(fun, ...) + box.begin() + return atomic_tail(pcall(fun, ...)) +end + -- box.commit yields, so it's defined as Lua/C binding -- box.rollback yields as well diff --git a/test/box/misc.result b/test/box/misc.result index e8ff1436196776119044019c9655b43fe215e8ba..cf56fd4750b201663fc02c67673e97758b78c94e 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -55,7 +55,8 @@ t = {} for n in pairs(box) do table.insert(t, tostring(n)) end table.sort(t) ... t --- -- - backup +- - atomic + - backup - begin - cfg - commit diff --git a/test/box/transaction.result b/test/box/transaction.result index 9c24d1f7b28aae8a88a4fd79ae91e62c26666bd3..746f7e12c23067cc2f4149e0b23c8a7e37d3e76e 100644 --- a/test/box/transaction.result +++ b/test/box/transaction.result @@ -423,3 +423,83 @@ function gh_1638() box.begin(); box.rollback() end for i = 1, 1000 do fiber.create(function() gh_1638() end) end --- ... +-- +--gh-818 add atomic() +-- +space = box.schema.space.create('atomic') +--- +... +index = space:create_index('primary') +--- +... +test_run:cmd("setopt delimiter ';'") +--- +- true +... +function args(...) + return 'args', ... +end; +--- +... +box.atomic(args, 1, 2, 3, 4, 5); +--- +- args +- 1 +- 2 +- 3 +- 4 +- 5 +... +function tx() + space:auto_increment{'first row'} + space:auto_increment{'second row'} + return space:select{} +end; +--- +... +box.atomic(tx); +--- +- - [1, 'first row'] + - [2, 'second row'] +... +function tx_error(space) + space:auto_increment{'third'} + space:auto_increment{'fourth'} + error("some error") +end; +--- +... +box.atomic(tx_error, space); +--- +- error: '[string "function tx_error(space) space:auto_incre..."]:1: some error' +... +function nested(space) + box.begin() +end; +--- +... +box.atomic(nested, space); +--- +- error: 'Operation is not permitted when there is an active transaction ' +... +function rollback(space) + space:auto_increment{'fifth'} + box.rollback() +end; +--- +... +box.atomic(rollback, space); +--- +... +test_run:cmd("setopt delimiter ''"); +--- +- true +... +space:select{} +--- +- - [1, 'first row'] + - [2, 'second row'] +... +space:drop() +--- +... diff --git a/test/box/transaction.test.lua b/test/box/transaction.test.lua index 22e6e6cca901eb6e7d3eab53f2d10b1aa4e2c0d9..cda0eb151a08b9294ec3e9a8669858140e2c22d9 100644 --- a/test/box/transaction.test.lua +++ b/test/box/transaction.test.lua @@ -195,3 +195,45 @@ box.space.test:drop() -- function gh_1638() box.begin(); box.rollback() end for i = 1, 1000 do fiber.create(function() gh_1638() end) end + +-- +--gh-818 add atomic() +-- +space = box.schema.space.create('atomic') +index = space:create_index('primary') +test_run:cmd("setopt delimiter ';'") + +function args(...) + return 'args', ... +end; +box.atomic(args, 1, 2, 3, 4, 5); + +function tx() + space:auto_increment{'first row'} + space:auto_increment{'second row'} + return space:select{} +end; +box.atomic(tx); + +function tx_error(space) + space:auto_increment{'third'} + space:auto_increment{'fourth'} + error("some error") +end; +box.atomic(tx_error, space); + +function nested(space) + box.begin() +end; +box.atomic(nested, space); + +function rollback(space) + space:auto_increment{'fifth'} + box.rollback() +end; +box.atomic(rollback, space); + +test_run:cmd("setopt delimiter ''"); +space:select{} + +space:drop()