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
Lua serializers should use FFI to check and set options #4521
Comments
The similar issue about box.cfg{} is #2867. |
Considering existing API and dubious benefits of FFI usage, the implementation of |
It has nothing to do with speed. What benchmarks we are talking about? This is just options, for Lua. This is only about ease of usage. Current implementation is a spaghetti of lua C API usage and Lua code. And why it is less convenient? It allows to drop lots of lua C code trying to update a table + a structure simultaneously. It is inconvenient now. |
@Gerold103, I guess you're confused a little with my comment. I totally agree with your remark about Lua + C spaghetti and two separate sources, that need to be synced after every update, and I'm all for the idea you proposed above. I wrote that FFI usage seems to be an inconvenient way to implement your proposal. Considering msgpuck/yaml/json initialization on Tarantool start phase and the lack of C API for manipulating with Benchmarks I mentioned in my comment can show the performance deviation, introduced as a result of the patch to be made. Feel free to correct me if I'm wrong: |
Is it possible to expose a C structure to Lua not via FFI? The point is to remove Lua C API usage, which would not be possible if a serializer would be a userdata. |
OK, now I don't get it.
I see the Serializer seems to be a simple entity, obtainable in Lua and C, having the following overloaded metamethods: |
Userdata way won't be really different in terms of complexity, what makes this issue useless. It was about simplification, and userdata won't solve it. Actually I don't care really much so as to continue arguing. Do whatever you consider right. |
We discussed this voicely and Igor said that creation and instantiation of a cdata type from C code is tricky and requires luaL_loadstring() calls that looks hacky. However I looked over the code and it seems that all necessary tricks are already encapsulated in src/lua/utils.c. So both ways looks equivalent for me except that cdata field accesses will be possibly faster. |
The main problem I see for now, that Since I'm neither the ticket author nor its assignee, I do not insist on the approach and @OKriw can compare both mentioned approaches and choose any of them she consider more convenient. My initial comment was only a dump of our recent offline discussion. |
As we had agreed with @Totktonada and @igormunkin we need to try both cases and see which way is better/faster. I have implemented userdata+ metatable variant, however at the moment it may be pointless even to test i, due to #4770 . Because patch that turns on __pairs/ipairs metamethod might be reverted. |
@Gerold103, the FFI approach has the one killing benefit: LuaJIT takes into account the @OKriw, I left a pure Lua PoC of implementing the pairs for an FFI structure below, please consider it: local ffi = require('ffi')
local function buildcdef(name, struct)
local cdef = string.format("struct %s {", name)
for field, ftype in pairs(struct) do
cdef = cdef .. string.format('%s %s;', ftype, field)
end
return cdef .. '};'
end
local struct = {
encode_sparse_convert = 'int',
encode_sparse_ratio = 'int',
encode_sparse_safe = 'int',
encode_max_depth = 'int',
encode_deep_as_nil = 'int',
encode_invalid_numbers = 'int',
encode_number_precision = 'int',
encode_load_metatables = 'int',
encode_use_tostring = 'int',
encode_invalid_as_nil = 'int',
decode_invalid_numbers = 'int',
decode_save_metatables = 'int',
decode_max_depth = 'int',
}
ffi.cdef(buildcdef('serializer', struct))
local serializer = ffi.metatype('struct serializer', {
__pairs = function(s)
return function(s, field)
local name = next(struct, field)
if not name then return nil end
return name, s[name]
end, s, nil
end
})
local json = ffi.new(serializer,
1, -- encode_sparse_convert
2, -- encode_sparse_ratio
10, -- encode_sparse_safe
128, -- encode_max_depth
0, -- encode_deep_as_nil
1, -- encode_invalid_numbers
14, -- encode_number_precision
1, -- encode_load_metatables
0, -- encode_use_tostring
0, -- encode_invalid_as_nil
1, -- decode_invalid_numbers
1, -- decode_save_metatables
128, -- decode_max_depth
)
for k, v in pairs(json) do print(k, v) end |
After 676369b we have 'on update' triggers, which should be fired at serializer options updates. Is there way to keep this with cdata-based config? |
It seems, no. tarantool> ffi = require('ffi')
tarantool> ffi.cdef([[struct foo { int x; };]])
tarantool> ffi.metatype('struct foo', {__index = function(...) print('__index', ...) end, __newindex = function(...) print('__newindex', ...) end})
tarantool> f = ffi.new('struct foo')
tarantool> f.y = 42
__newindex cdata<struct foo>: 0x41dc7ca8 y 42
---
...
tarantool> f.x = 42
---
... |
I mean, it does not work neither of the ways:
OTOH, it seems, we can define a structure with one ( |
NB: Don't forget about tab-completion of the options:
|
There are several modules in Lua allowing to transform data from one format to another. YAML, Msgpack, Msgpackffi, JSON. They are available as
require('msgpack'), require('yaml'), require('json')
. They provide methodcfg{}
. It takes a dictionary of options to update. The options are members ofstruct luaL_serializer
object in C.The problem is that this structure needs to be visible in Lua. For example, so as it would be possible to check
msgpack.cfg.encode_max_depth
. Currently it is implemented quite inaccurate. Any update ofstruct luaL_serializer
is copied manually to its Lua table, inluaL_serializer_cfg()
.A better solution would be to declare
struct luaL_serializer
viaffi
in Lua, and directly read and update the C structure. It would allow to dropluaL_serializer_cfg()
, other related functions, and will solve a bug, that a user can do:<serializer>.cfg.<key> = <value>
instead of<serializer>.cfg({<key> = <value>})
, it won't update any options in fact, and the user won't get an error either. After the patch both ways should work the same.The text was updated successfully, but these errors were encountered: