Skip to content

Commit

Permalink
crud: support vshard identification by name
Browse files Browse the repository at this point in the history
In vshard 0.1.25, new feature related to vshard configuration and
storage info was introduced [1]. If the new mode is used, crud module
fails to bootstrap and work in several places. This feature is enabled
by Tarantool 3.0 if vshard cluster was configured with 3.0 config.

After this patch, it is possible to bootstrap a vshard cluster with
new configuration mode. We run all existing vshard tests with new modes
after this patch. Module code was updated to support both possible mods.

1. tarantool/vshard#426

Closes #403
  • Loading branch information
DifferentialOrange committed Dec 25, 2023
1 parent 48f801c commit be4c06d
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 72 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test_on_push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ jobs:
cartridge-version: "2.8.0"
- tarantool-version: "2.11"
metrics-version: "1.0.0"
vshard-version: "0.1.24"
vshard-version: "0.1.25"
- tarantool-version: "2.11"
external-merger-version: "0.0.5"
external-keydef-version: "0.0.4"
- tarantool-version: "master"
metrics-version: "1.0.0"
vshard-version: "0.1.24"
vshard-version: "0.1.25"
fail-fast: false
# Can't install older versions on 22.04,
# see https://github.com/tarantool/setup-tarantool/issues/36
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## Unreleased

### Fixed
* Compatibility with vshard 0.1.25 `name_as_key` identification mode
for Tarantool 3.0 (#403).

## [1.4.1] - 23-10-23

### Changed
Expand Down
18 changes: 3 additions & 15 deletions crud.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ local stats = require('crud.stats')
local readview = require('crud.readview')
local schema = require('crud.schema')

local vshard = require('vshard')
local luri = require('uri')

local crud = {}
Expand Down Expand Up @@ -174,25 +173,14 @@ function crud.init_storage()

local user = nil
if not box.info.ro then
local ok, storage_info = pcall(vshard.storage.info)
if not ok then
error('vshard.storage.cfg() must be called first')
end
local replicaset_uuid, replicaset = utils.get_self_vshard_replicaset()

local box_info = box.info()
local replicaset_uuid
if box_info.replicaset ~= nil then
replicaset_uuid = box_info.replicaset.uuid
else
replicaset_uuid = box_info.cluster.uuid
end
local replicaset_info = storage_info.replicasets[replicaset_uuid]
if replicaset_info == nil or replicaset_info.master == nil then
if replicaset == nil or replicaset.master == nil then
error(string.format('Failed to find a vshard configuration for ' ..
' replicaset with replicaset_uuid %s.',
replicaset_uuid))
end
user = luri.parse(replicaset_info.master.uri).login or 'guest'
user = luri.parse(replicaset.master.uri).login or 'guest'
end

if rawget(_G, '_crud') == nil then
Expand Down
45 changes: 35 additions & 10 deletions crud/common/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ function utils.format_replicaset_error(replicaset_uuid, msg, ...)
end

local function get_replicaset_by_replica_uuid(replicasets, uuid)
for replicaset_uuid, replicaset in pairs(replicasets) do
for replica_uuid, _ in pairs(replicaset.replicas) do
if replica_uuid == uuid then
return replicasets[replicaset_uuid]
for _, replicaset in pairs(replicasets) do
for _, replica in pairs(replicaset.replicas) do
if replica.uuid == uuid then
return replicaset
end
end
end
Expand Down Expand Up @@ -1143,23 +1143,23 @@ function utils.storage_info(opts)
local timeout = opts.timeout or const.DEFAULT_VSHARD_CALL_TIMEOUT

for _, replicaset in pairs(replicasets) do
for replica_uuid, replica in pairs(replicaset.replicas) do
replica_state_by_uuid[replica_uuid] = {
for _, replica in pairs(replicaset.replicas) do
replica_state_by_uuid[replica.uuid] = {
status = "error",
is_master = replicaset.master == replica
}
local ok, res = pcall(replica.conn.call, replica.conn, CRUD_STORAGE_INFO_FUNC_NAME,
{}, async_opts)
if ok then
futures_by_replicas[replica_uuid] = res
futures_by_replicas[replica.uuid] = res
else
local err_msg = string.format("Error getting storage info for %s", replica_uuid)
local err_msg = string.format("Error getting storage info for %s", replica.uuid)
if res ~= nil then
log.error("%s: %s", err_msg, res)
replica_state_by_uuid[replica_uuid].message = tostring(res)
replica_state_by_uuid[replica.uuid].message = tostring(res)
else
log.error(err_msg)
replica_state_by_uuid[replica_uuid].message = err_msg
replica_state_by_uuid[replica.uuid].message = err_msg
end
end
end
Expand Down Expand Up @@ -1314,4 +1314,29 @@ function utils.is_cartridge_hotreload_supported()
return true, cartridge_hotreload
end

function utils.get_self_vshard_replicaset()
local box_info = box.info()

local ok, storage_info = pcall(vshard.storage.info)
assert(ok, 'vshard.storage.cfg() must be called first')

local replicaset_uuid
if box_info.replicaset ~= nil then
replicaset_uuid = box_info.replicaset.uuid
else
replicaset_uuid = box_info.cluster.uuid
end

local replicaset
-- Identification key may be name since vshard 0.1.25.
-- See also https://github.com/tarantool/vshard/issues/460.
for _, v in pairs(storage_info.replicasets) do
if v.uuid == replicaset_uuid then
replicaset = v
end
end

return replicaset_uuid, replicaset
end

return utils
6 changes: 3 additions & 3 deletions crud/readview.lua
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,16 @@ function Readview_obj:close(opts)

local errors = {}
for _, replicaset in pairs(replicasets) do
for replica_uuid, replica in pairs(replicaset.replicas) do
for _, replica in pairs(replicaset.replicas) do
for _, value in pairs(self._uuid) do
if replica_uuid == value.uuid then
if replica.uuid == value.uuid then
local replica_result, replica_err = replica.conn:call(CRUD_CLOSE_FUNC_NAME,
{self._uuid}, {timeout = opts.timeout})
if replica_err ~= nil then
table.insert(errors, ReadviewError:new("Failed to close Readview on storage: %s", replica_err))
end
if replica_err == nil and (not replica_result) then
table.insert(errors, ReadviewError:new("Readview was not found on storage: %s", replica_uuid))
table.insert(errors, ReadviewError:new("Readview was not found on storage: %s", replica.uuid))
end
end
end
Expand Down
68 changes: 53 additions & 15 deletions test/helper.lua
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ end

function helpers.get_test_vshard_sharding()
local sharding = {
{
['s-1'] = {
replicas = {
['s1-master'] = {
instance_uuid = helpers.uuid('b', 1),
Expand All @@ -243,7 +243,7 @@ function helpers.get_test_vshard_sharding()
},
},
},
{
['s-2'] = {
replicas = {
['s2-master'] = {
instance_uuid = helpers.uuid('c', 1),
Expand Down Expand Up @@ -361,12 +361,12 @@ function helpers.get_other_storage_bucket_id(cluster, bucket_id)
local replicasets = vshard.router.routeall()
local other_replicaset_uuid
for replicaset_uuid, replicaset in pairs(replicasets) do
local other_replicaset
for _, replicaset in pairs(replicasets) do
local stat, err = replicaset:callrw('vshard.storage.bucket_stat', {bucket_id})
if err ~= nil and err.name == 'WRONG_BUCKET' then
other_replicaset_uuid = replicaset_uuid
other_replicaset = replicaset
break
end
Expand All @@ -378,13 +378,8 @@ function helpers.get_other_storage_bucket_id(cluster, bucket_id)
end
end
if other_replicaset_uuid == nil then
return nil, 'Other replicaset is not found'
end
local other_replicaset = replicasets[other_replicaset_uuid]
if other_replicaset == nil then
return nil, string.format('Replicaset %s not found', other_replicaset_uuid)
return nil, 'Other replicaset is not found'
end
local buckets_info = other_replicaset:callrw('vshard.storage.buckets_info')
Expand Down Expand Up @@ -734,7 +729,7 @@ function helpers.start_cluster(g, cartridge_cfg, vshard_cfg)
local cfg = table.deepcopy(vshard_cfg)
cfg.engine = g.params.engine

g.cfg = vtest.config_new(cfg)
g.cfg = vtest.config_new(cfg, g.params.backend_cfg)
vtest.cluster_new(g, g.cfg)
g.cfg.engine = nil
end
Expand All @@ -756,14 +751,57 @@ function helpers.get_router(cluster, backend)
end
end

function helpers.parse_module_version(str)
-- https://github.com/tarantool/luatest/blob/f37b353b77be50a1f1ce87c1ff2edf0c1b96d5d1/luatest/utils.lua#L166-L173
local splitstr = str:split('.')
local major = tonumber(splitstr[1]:match('%d+'))
local minor = tonumber(splitstr[2]:match('%d+'))
local patch = tonumber(splitstr[3]:match('%d+'))
return luatest_utils.version(major, minor, patch)
end

function helpers.is_name_supported_as_vshard_id()
local vshard_version = helpers.parse_module_version(require('vshard')._VERSION)
local is_vshard_supports = luatest_utils.version_ge(vshard_version,
luatest_utils.version(0, 1, 25))

local tarantool_version = luatest_utils.get_tarantool_version()
local is_tarantool_supports = luatest_utils.version_ge(tarantool_version,
luatest_utils.version(3, 0, 0))
return is_vshard_supports and is_tarantool_supports
end

function helpers.backend_matrix(base_matrix)
base_matrix = base_matrix or {{}}
local backends = {helpers.backend.VSHARD, helpers.backend.CARTRIDGE}
local backend_params = {
{
backend = helpers.backend.CARTRIDGE,
backend_cfg = nil,
},
}

if helpers.is_name_supported_as_vshard_id() then
table.insert(backend_params, {
backend = helpers.backend.VSHARD,
backend_cfg = {identification_mode = 'uuid_as_key'},
})
table.insert(backend_params, {
backend = helpers.backend.VSHARD,
backend_cfg = {identification_mode = 'name_as_key'},
})
else
table.insert(backend_params, {
backend = helpers.backend.VSHARD,
backend_cfg = nil,
})
end

local matrix = {}
for _, backend in ipairs(backends) do
for _, params in ipairs(backend_params) do
for _, base in ipairs(base_matrix) do
base = table.deepcopy(base)
base.backend = backend
base.backend = params.backend
base.backend_cfg = params.backend_cfg
table.insert(matrix, base)
end
end
Expand Down
6 changes: 3 additions & 3 deletions test/performance/perf_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,23 @@ end

local vshard_cfg_template = {
sharding = {
{
['s-1'] = {
replicas = {
['s1-master'] = {
master = true,
},
['s1-replica'] = {},
},
},
{
['s-2'] = {
replicas = {
['s2-master'] = {
master = true,
},
['s2-replica'] = {},
},
},
{
['s-3'] = {
replicas = {
['s3-master'] = {
master = true,
Expand Down
4 changes: 2 additions & 2 deletions test/unit/call_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ local pgroup = t.group('call', helpers.backend_matrix())

local vshard_cfg_template = {
sharding = {
{
['s-1'] = {
replicas = {
['s1-master'] = {
master = true,
},
['s1-replica'] = {},
},
},
{
['s-2'] = {
replicas = {
['s2-master'] = {
master = true,
Expand Down
2 changes: 1 addition & 1 deletion test/unit/not_initialized_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ local pgroup = t.group('not-initialized', helpers.backend_matrix({

local vshard_cfg_template = {
sharding = {
{
storages = {
replicas = {
storage = {
master = true,
Expand Down
1 change: 1 addition & 0 deletions test/unit/stats_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ local function enable_stats(g, params)
if params ~= nil then
params = table.deepcopy(params)
params.backend = nil
params.backend_cfg = nil
end
g.router:eval("stats_module.enable(...)", { params })
end
Expand Down
17 changes: 17 additions & 0 deletions test/vshard_helpers/server.lua
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,23 @@ function Server:replicaset_uuid()
return uuid
end

function Server:replicaset_name()
-- Cache the value when found it first time.
if self.replicaset_name_value then
return self.replicaset_name_value
end
local name = self:exec(function()
local info = box.info
if info.replicaset then
return info.replicaset.name
end
return nil
end)

self.replicaset_uuid_value = name
return name
end

function Server:election_term()
return self:exec(function() return box.info.election.term end)
end
Expand Down
Loading

0 comments on commit be4c06d

Please sign in to comment.