diff --git a/test/helper.lua b/test/helper.lua index 4c56385bb..58d46fc8b 100644 --- a/test/helper.lua +++ b/test/helper.lua @@ -179,6 +179,76 @@ function helpers.call_on_servers(cluster, aliases, func) end end +-- Call given function for each server with the 'crud-storage' +-- role. +-- +-- 'func' accepts a server object, a replicaset config and all +-- arguments passed after 'func'. +-- +-- Usage example: +-- +-- | local res = {} +-- | helpers.call_on_storages(g.cluster, function(server, replicaset, res) +-- | local instance_res = server.net_box:call(<...>) +-- | res[replicaset.alias] = res[replicaset.alias] + instance_res +-- | end) +-- | t.assert_equals(res, {['s-1'] = 5, ['s-2'] = 6}) +function helpers.call_on_storages(cluster, func, ...) + -- Accumulate storages into a map from the storage alias to + -- the replicaset object. Only storages, skip other instances. + -- + -- Example: + -- + -- | { + -- | ['s1-master'] = { + -- | alias = 's-1', + -- | roles = <...>, + -- | servers = { + -- | { + -- | alias = 's1-master', + -- | env = <...>, + -- | instance_uuid = <...>, + -- | }, + -- | <...> + -- | }, + -- | uuid = <...>, + -- | } + -- | ['s1-replica'] = <...>, + -- | ['s2-master'] = <...>, + -- | ['s2-replica'] = <...>, + -- | } + -- + -- NB: The 'servers' field contains server configs. They are + -- not the same as server objects: say, there is no 'net_box' + -- field here. + local alias_map = {} + for _, replicaset in ipairs(cluster.replicasets) do + -- Whether it is a storage replicaset? + local has_crud_storage_role = false + for _, role in ipairs(replicaset.roles) do + if role == 'crud-storage' then + has_crud_storage_role = true + break + end + end + + -- If so, add servers of the replicaset into the mapping. + if has_crud_storage_role then + for _, server in ipairs(replicaset.servers) do + alias_map[server.alias] = replicaset + end + end + end + + -- Call given function for each storage node. + for _, server in ipairs(cluster.servers) do + local replicaset_alias = alias_map[server.alias] + if replicaset_alias ~= nil then + func(server, replicaset_alias, ...) + end + end +end + function helpers.assert_ge(actual, expected, message) if not (actual >= expected) then local err = string.format('expected: %s >= %s', actual, expected) diff --git a/test/helpers/storage_stat.lua b/test/helpers/storage_stat.lua new file mode 100644 index 000000000..63cdd1681 --- /dev/null +++ b/test/helpers/storage_stat.lua @@ -0,0 +1,98 @@ +local checks = require('checks') +local helpers = require('test.helper') + +local storage_stat = {} + +-- Wrap crud's select_on_storage() function to count selects +-- and add storage_stat() function that returns resulting +-- statistics. +-- +-- Call it after crud's initialization. +function storage_stat.init_on_storage() + assert(_G._crud.select_on_storage ~= nil) + + -- Here we count requests. + local storage_stat_table = { + select_requests = 0, + } + + -- Wrap select_on_storage() function. + local select_on_storage_saved = _G._crud.select_on_storage + _G._crud.select_on_storage = function(...) + local requests = storage_stat_table.select_requests + storage_stat_table.select_requests = requests + 1 + return select_on_storage_saved(...) + end + + -- Accessor for the statistics. + rawset(_G, 'storage_stat', function() + return storage_stat_table + end) +end + +-- Accumulate statistics from storages. +-- +-- The statistics is grouped by replicasets. +-- +-- Example of a return value: +-- +-- | { +-- | ['s-1'] = { +-- | select_requests = 1, +-- | }, +-- | ['s-2'] = { +-- | select_requests = 0, +-- | }, +-- | } +function storage_stat.collect(cluster) + checks('table') + + local res = {} + + helpers.call_on_storages(cluster, function(server, replicaset) + checks('table', 'table') + + -- Collect the statistics. + local storage_stat = server.net_box:call('storage_stat') + + -- Initialize if needed. + if res[replicaset.alias] == nil then + res[replicaset.alias] = {} + end + + -- Accumulate the collected statistics. + for key, val in pairs(storage_stat) do + local old = res[replicaset.alias][key] or 0 + res[replicaset.alias][key] = old + val + end + end) + + return res +end + +-- Difference between 'a' and 'b' storage statistics. +-- +-- The return value structure is the same as for +-- storage_stat.collect(). +function storage_stat.diff(a, b) + checks('table', 'table') + + local diff = table.deepcopy(a) + + for replicaset_alias, stat_b in pairs(b) do + -- Initialize if needed. + if diff[replicaset_alias] == nil then + diff[replicaset_alias] = {} + end + + -- Substract 'b' statistics from 'a'. + for key, val in pairs(stat_b) do + local old = diff[replicaset_alias][key] or 0 + diff[replicaset_alias][key] = old - val + end + end + + return diff +end + +return storage_stat