diff --git a/src/luamod.lua b/src/luamod.lua index f7237aedb3daf0dac9d3b1c76bfefc7f5c0f5fdb..ef45685d6d6d340a6206f0a9c632eb73dfacbdb7 100644 --- a/src/luamod.lua +++ b/src/luamod.lua @@ -104,7 +104,8 @@ local function is_retriable_error(error) return false end --- Performs a reenterable schema change CaS request. +-- Performs a reenterable schema change CaS request. On success returns an index +-- of the proposed raft entry. -- -- Params: -- @@ -119,6 +120,12 @@ end -- It is called after raft_read_index and after any pending schema -- change has been finalized. -- +-- Returns: +-- +-- (number) raft index +-- or +-- (nil, error) in case of an error +-- local function reenterable_schema_change_request(deadline, make_op_if_needed) while true do ::retry:: @@ -909,6 +916,10 @@ Drops a space on each instance of the cluster. Waits for the space to be dropped globally or returns an error if the timeout is reached before that. +Skips the request if the space doesn't exist. + +NOTE: If this function returns a timeout error, the space may have been locally +dropped and in the future the change can either be committed or rolled back. Params: @@ -938,42 +949,49 @@ function pico.drop_space(space, opts) return nil, err end - local space_id - if type(space) == 'string' then - local space_def = box.space._pico_space.index.name:get(space) - if space_def == nil then - return nil, box.error.new(box.error.NO_SUCH_SPACE, space) + local deadline = fiber.clock() + opts.timeout + + local should_wait_for_ddl_fin = true + + -- XXX: we construct this closure every time the function is called, + -- which is bad for performance/jit. Refactor if problems are discovered. + local function make_op_if_needed() + local space_def = nil + if type(space) == 'string' then + space_def = box.space._pico_space.index.name:get(space) + elseif type(space) == 'number' then + space_def = box.space._pico_space:get(space) end - space_id = space_def.id - elseif type(space) == 'number' then - space_id = space - if box.space._pico_space:get(space_id) == nil then - return nil, box.error.new(box.error.NO_SUCH_SPACE, space) + if space_def == nil then + -- Space doesn't exist yet, no op needed + should_wait_for_ddl_fin = false + return nil end - end - local op = { - kind = 'ddl_prepare', - schema_version = next_schema_version(), - ddl = { - kind = 'drop_space', - id = space_id, + return { + kind = 'ddl_prepare', + schema_version = next_schema_version(), + ddl = { + kind = 'drop_space', + id = space_def.id, + } } - } + end - local timeout = opts.timeout - local ok, err = pico._prepare_schema_change(op, timeout) - if not ok then + local index, err = reenterable_schema_change_request(deadline, make_op_if_needed) + if index == nil then return nil, err end - local index = ok - local ok, err = pico.wait_ddl_finalize(index, { timeout = timeout }) - if not ok then + if not should_wait_for_ddl_fin then + return index + end + + local fin_index, err = pico.wait_ddl_finalize(index, { timeout = deadline - fiber.clock() }) + if fin_index == nil then return nil, err end - local fin_index = ok return fin_index end diff --git a/test/int/test_ddl.py b/test/int/test_ddl.py index 51fbaa167444acb95da7311b435a715af5bb6823..1e70c63f2c3b40135dc1358e90a481b6c30e5f70 100644 --- a/test/int/test_ddl.py +++ b/test/int/test_ddl.py @@ -100,15 +100,11 @@ def test_ddl_lua_api(cluster: Cluster): # pico.drop_space # - # No such space name -> error. - with pytest.raises( - ReturnError, match="Space 'Space does not exist' does not exist" - ): - cluster.drop_space("Space does not exist") + # No such space name -> ok. + cluster.drop_space("Space does not exist") - # No such space id -> error. - with pytest.raises(ReturnError, match="Space '69105' does not exist"): - cluster.drop_space(69105) + # No such space id -> ok. + cluster.drop_space(69105) # Ok by name. cluster.drop_space("some_name")