-
Notifications
You must be signed in to change notification settings - Fork 15
Support custom sharding func #239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
e820c9f
Replace sharding methods in new directory `sharding`
AnaNek cc69113
Copy the content of `sharding_key.lua` file to `sharding_metadata.lua…
AnaNek 02e6fb1
Separate common sharding metadata methods from sharding key methods
AnaNek 2ed4841
Fix filling sharding key cache when sharding key data is incorrect
AnaNek 6b7151c
Add functions from `ddl` for sharding func module
AnaNek 2887e18
Add support of custom sharding func for crud methods
AnaNek File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
local errors = require('errors') | ||
local log = require('log') | ||
|
||
local dev_checks = require('crud.common.dev_checks') | ||
local cache = require('crud.common.sharding.sharding_metadata_cache') | ||
local utils = require('crud.common.utils') | ||
|
||
local ShardingFuncError = errors.new_class('ShardingFuncError', {capture_stack = false}) | ||
|
||
local sharding_func_module = {} | ||
|
||
local function is_callable(object) | ||
if type(object) == 'function' then | ||
return true | ||
end | ||
|
||
-- all objects with type `cdata` are allowed | ||
-- because there is no easy way to get | ||
-- metatable.__call of object with type `cdata` | ||
if type(object) == 'cdata' then | ||
return true | ||
end | ||
|
||
local object_metatable = getmetatable(object) | ||
if (type(object) == 'table' or type(object) == 'userdata') then | ||
-- if metatable type is not `table` -> metatable is protected -> | ||
-- cannot detect metamethod `__call` exists | ||
if object_metatable and type(object_metatable) ~= 'table' then | ||
return true | ||
end | ||
|
||
-- `__call` metamethod can be only the `function` | ||
-- and cannot be a `table` | `userdata` | `cdata` | ||
-- with `__call` methamethod on its own | ||
if object_metatable and object_metatable.__call then | ||
return type(object_metatable.__call) == 'function' | ||
end | ||
end | ||
|
||
return false | ||
end | ||
|
||
local function get_function_from_G(func_name) | ||
ligurio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
local chunks = string.split(func_name, '.') | ||
local sharding_func = _G | ||
|
||
-- check is the each chunk an identifier | ||
for _, chunk in pairs(chunks) do | ||
if not utils.check_name_isident(chunk) or sharding_func == nil then | ||
return nil | ||
end | ||
sharding_func = rawget(sharding_func, chunk) | ||
end | ||
|
||
return sharding_func | ||
end | ||
|
||
local function as_callable_object(sharding_func_def, space_name) | ||
if type(sharding_func_def) == 'string' then | ||
local sharding_func = get_function_from_G(sharding_func_def) | ||
if sharding_func ~= nil and is_callable(sharding_func) == true then | ||
return sharding_func | ||
end | ||
end | ||
|
||
if type(sharding_func_def) == 'table' then | ||
local sharding_func, err = loadstring('return ' .. sharding_func_def.body) | ||
if sharding_func == nil then | ||
return nil, ShardingFuncError:new( | ||
"Body is incorrect in sharding_func for space (%s): %s", space_name, err) | ||
end | ||
return sharding_func() | ||
end | ||
|
||
return nil, ShardingFuncError:new( | ||
"Wrong sharding function specified in _ddl_sharding_func space for (%s) space", space_name | ||
) | ||
end | ||
|
||
function sharding_func_module.construct_as_callable_obj_cache(metadata_map, specified_space_name) | ||
dev_checks('table', 'string') | ||
|
||
local result_err | ||
|
||
cache.sharding_func_map = {} | ||
for space_name, metadata in pairs(metadata_map) do | ||
if metadata.sharding_func_def ~= nil then | ||
local sharding_func, err = as_callable_object(metadata.sharding_func_def, | ||
space_name) | ||
if err ~= nil then | ||
if specified_space_name == space_name then | ||
result_err = err | ||
log.error(err) | ||
else | ||
log.warn(err) | ||
end | ||
end | ||
|
||
cache.sharding_func_map[space_name] = sharding_func | ||
Totktonada marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
end | ||
|
||
return result_err | ||
end | ||
|
||
sharding_func_module.internal = { | ||
as_callable_object = as_callable_object, | ||
is_callable = is_callable, | ||
} | ||
|
||
return sharding_func_module |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
local errors = require('errors') | ||
local log = require('log') | ||
|
||
local dev_checks = require('crud.common.dev_checks') | ||
local cache = require('crud.common.sharding.sharding_metadata_cache') | ||
local utils = require('crud.common.utils') | ||
|
||
local ShardingKeyError = errors.new_class("ShardingKeyError", {capture_stack = false}) | ||
local WrongShardingConfigurationError = errors.new_class('WrongShardingConfigurationError', {capture_stack = false}) | ||
|
||
local sharding_key_module = {} | ||
|
||
-- Build a structure similar to index, but it is not a real index object, | ||
-- it contains only parts key with fieldno's. | ||
local function as_index_object(space_name, space_format, sharding_key_def) | ||
dev_checks('string', 'table', 'table') | ||
|
||
local fieldnos = {} | ||
local fieldno_map = utils.get_format_fieldno_map(space_format) | ||
for _, field_name in ipairs(sharding_key_def) do | ||
local fieldno = fieldno_map[field_name] | ||
if fieldno == nil then | ||
return nil, WrongShardingConfigurationError:new( | ||
"No such field (%s) in a space format (%s)", field_name, space_name) | ||
end | ||
table.insert(fieldnos, {fieldno = fieldno}) | ||
end | ||
|
||
return {parts = fieldnos} | ||
end | ||
|
||
-- Make sure sharding key definition is a part of primary key. | ||
local function is_part_of_pk(space_name, primary_index_parts, sharding_key_as_index_obj) | ||
dev_checks('string', 'table', 'table') | ||
|
||
if cache.is_part_of_pk[space_name] ~= nil then | ||
return cache.is_part_of_pk[space_name] | ||
end | ||
|
||
local is_part_of_pk = true | ||
local pk_fieldno_map = utils.get_index_fieldno_map(primary_index_parts) | ||
for _, part in ipairs(sharding_key_as_index_obj.parts) do | ||
if pk_fieldno_map[part.fieldno] == nil then | ||
is_part_of_pk = false | ||
break | ||
end | ||
end | ||
cache.is_part_of_pk[space_name] = is_part_of_pk | ||
|
||
return is_part_of_pk | ||
end | ||
|
||
-- Build an array with sharding key values. Function extracts those values from | ||
-- primary key that are part of sharding key (passed as index object). | ||
local function extract_from_index(primary_key, primary_index_parts, sharding_key_as_index_obj) | ||
dev_checks('table', 'table', 'table') | ||
|
||
-- TODO: extract_from_index() calculates primary_index_parts on each | ||
-- request. It is better to cache it's value. | ||
-- https://github.com/tarantool/crud/issues/243 | ||
local primary_index_fieldno_map = utils.get_index_fieldno_map(primary_index_parts) | ||
|
||
local sharding_key = {} | ||
for _, part in ipairs(sharding_key_as_index_obj.parts) do | ||
-- part_number cannot be nil because earlier we checked that tuple | ||
-- field names defined in sharding key definition are part of primary | ||
-- key. | ||
local part_number = primary_index_fieldno_map[part.fieldno] | ||
assert(part_number ~= nil) | ||
local field_value = primary_key[part_number] | ||
table.insert(sharding_key, field_value) | ||
end | ||
|
||
return sharding_key | ||
end | ||
|
||
-- Extract sharding key from pk. | ||
-- Returns a table with sharding key or pair of nil and error. | ||
function sharding_key_module.extract_from_pk(space_name, sharding_key_as_index_obj, primary_index_parts, primary_key) | ||
dev_checks('string', '?table', 'table', '?') | ||
|
||
if sharding_key_as_index_obj == nil then | ||
return primary_key | ||
end | ||
|
||
local res = is_part_of_pk(space_name, primary_index_parts, sharding_key_as_index_obj) | ||
if res == false then | ||
return nil, ShardingKeyError:new( | ||
"Sharding key for space %q is missed in primary index, specify bucket_id", | ||
space_name | ||
) | ||
end | ||
if type(primary_key) ~= 'table' then | ||
primary_key = {primary_key} | ||
end | ||
|
||
return extract_from_index(primary_key, primary_index_parts, sharding_key_as_index_obj) | ||
end | ||
|
||
function sharding_key_module.construct_as_index_obj_cache(metadata_map, specified_space_name) | ||
dev_checks('table', 'string') | ||
|
||
local result_err | ||
|
||
cache.sharding_key_as_index_obj_map = {} | ||
for space_name, metadata in pairs(metadata_map) do | ||
if metadata.sharding_key_def ~= nil then | ||
local sharding_key_as_index_obj, err = as_index_object(space_name, | ||
metadata.space_format, | ||
metadata.sharding_key_def) | ||
if err ~= nil then | ||
if specified_space_name == space_name then | ||
result_err = err | ||
log.error(err) | ||
else | ||
log.warn(err) | ||
end | ||
end | ||
|
||
cache.sharding_key_as_index_obj_map[space_name] = sharding_key_as_index_obj | ||
end | ||
end | ||
|
||
return result_err | ||
end | ||
|
||
sharding_key_module.internal = { | ||
as_index_object = as_index_object, | ||
extract_from_index = extract_from_index, | ||
is_part_of_pk = is_part_of_pk, | ||
} | ||
|
||
return sharding_key_module |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.