Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions test/storage-luatest/storage_1_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -674,3 +674,55 @@ test_group.test_info_disable_consistency = function(g)
ilt.assert(res.is_enabled)
end, {global_cfg})
end

local function test_error_msg_is_preserved_template(add_to_schema, g)
g.replica_1_a:exec(function(add_to_schema)
rawset(_G, 'test_fail', function()
box.begin()
error('test_error')
end)
if add_to_schema then
box.schema.func.create('test_fail')
end
local status, err = ivshard.storage.call(1, 'read', 'test_fail', {})
ilt.assert_not(status)
local err_msg = tostring(err)
ilt.assert_str_contains(err_msg, 'test_error')
ilt.assert_not_str_contains(err_msg, 'Transaction is active')
rawset(_G, 'test_fail', nil)
if add_to_schema then
box.schema.func.drop('test_fail')
end
end, {add_to_schema})
end

test_group.test_error_msg_is_preserved = function(g)
test_error_msg_is_preserved_template(false, g)
test_error_msg_is_preserved_template(true, g)
end

local function test_local_call_return_type_consistency_template(
add_to_schema, g)
g.replica_1_a:exec(function(add_to_schema)
rawset(_G, 'test_return_tuple', function()
return box.tuple.new({100, 200, 'tuple'})
end)
if add_to_schema then
box.schema.func.create('test_return_tuple')
end
local status, result = ivshard.storage.call(
1, 'read', 'test_return_tuple', {})
ilt.assert(status)
ilt.assert_equals(type(result), 'table')
ilt.assert_equals(result, {100, 200, 'tuple'})
if add_to_schema then
box.schema.func.drop('test_return_tuple')
end
_G.test_return_tuple = nil
end, {add_to_schema})
end

test_group.test_local_call_return_type_consistency = function(g)
test_local_call_return_type_consistency_template(true, g)
test_local_call_return_type_consistency_template(false, g)
end
25 changes: 24 additions & 1 deletion vshard/storage/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ local trigger = require('internal.trigger')
local ffi = require('ffi')
local json_encode = require('json').encode
local yaml_encode = require('yaml').encode
local msgpack = require('msgpack')
local fiber_clock = lfiber.clock
local fiber_yield = lfiber.yield
local netbox_self = netbox.self
Expand Down Expand Up @@ -260,6 +261,23 @@ else
end
end

--
-- This is copy-paste from the net_box.lua handle_eval_result.
--
local function handle_results(status, ...)
if not status then
box.rollback()
return status, box.error.new(box.error.PROC_LUA, (...))
end
local results = {...}
for i = 1, select('#', ...) do
if type(results[i]) == 'cdata' then
results[i] = msgpack.decode(msgpack.encode(results[i]))
end
end
return status, unpack(results)
end

--
-- Invoke a function on this instance. Arguments are unpacked into the function
-- as arguments.
Expand All @@ -284,7 +302,12 @@ local_call = function(func_name, args)
if not func then
return pcall(netbox_self_call, netbox_self, func_name, args)
end
Comment on lines 302 to 304
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if my function left a transaction unfinished, and it was called via netbox_self_call(), then netbox_self_call() will roll it back?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. If the function throws an error during an active transaction, the transaction is rolled back in handle_eval_result. If the function leaves the transaction unfinished, it is rolled back after the function completes

return pcall(func.call, func, args)
-- If the function is called directly, fails, and leaves an uncommitted
-- transaction, then in Tarantool versions before 3.0.0-beta1-18,
-- the original error is replaced by the "Transaction is active" error.
-- We manually check if the function returned an error. If so, we
-- rollback the transaction to reveal the original error.
return handle_results(pcall(func.call, func, args))
end

end
Expand Down