From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> To: tarantool-patches@freelists.org Cc: kostja@tarantool.org Subject: [tarantool-patches] [PATCH 10/10] swim: cache members in Lua member table Date: Wed, 15 May 2019 22:36:38 +0300 [thread overview] Message-ID: <e71f7553b22ecdb6a442e83cb9c9f2ca379400a1.1557948687.git.v.shpilevoy@tarantool.org> (raw) In-Reply-To: <cover.1557948686.git.v.shpilevoy@tarantool.org> Each time a member was returned from a SWIM instance object, it was wrapped by a table with a special metatable, cached payload. But next the same lookup returned a new table. It - created garbage as a new member wrapper; - lost cached decoded payload. This commit caches in a private table all wrapped members and returns an existing wrapper on a next lookup. A microbenchmark showed, that cached result retrieval is 10 times faster, than each time create a new table. Cache table keeps week references - it means, that when a member object looses all its references in a user's application, it is automatically dropped from the table. Part of #3234 --- src/lua/swim.lua | 34 ++++++++++++++----- test/swim/swim.result | 75 +++++++++++++++++++++++++++++++++++++++++ test/swim/swim.test.lua | 30 +++++++++++++++++ 3 files changed, 130 insertions(+), 9 deletions(-) diff --git a/src/lua/swim.lua b/src/lua/swim.lua index 852192479..35ceea669 100644 --- a/src/lua/swim.lua +++ b/src/lua/swim.lua @@ -378,10 +378,19 @@ local swim_member_mt = { -- table-wrapper stores not only a pointer, but also cached -- decoded payload. -- -local function swim_member_wrap(ptr) - capi.swim_member_ref(ptr) - ffi.gc(ptr, capi.swim_member_unref) - return setmetatable({ptr = ptr}, swim_member_mt) +local function swim_wrap_member(s, ptr) + -- Lua tables can't normally work with cdata keys. Even when + -- cdata is a simple number, table can't do search by it. + local key = tonumber(ffi.cast('unsigned long', ptr)) + local cache = s.cache_table + local wrapped = cache[key] + if wrapped == nil then + capi.swim_member_ref(ptr) + ffi.gc(ptr, capi.swim_member_unref) + wrapped = setmetatable({ptr = ptr}, swim_member_mt) + cache[key] = wrapped + end + return wrapped end -- @@ -516,7 +525,8 @@ end -- into the member table. -- local function swim_self(s) - return swim_member_wrap(capi.swim_self(swim_check_instance(s, 'swim:self'))) + local ptr = swim_check_instance(s, 'swim:self') + return swim_wrap_member(s, capi.swim_self(ptr)) end -- @@ -530,7 +540,7 @@ local function swim_member_by_uuid(s, uuid) if m == nil then return nil end - return swim_member_wrap(m) + return swim_wrap_member(s, m) end -- @@ -590,13 +600,14 @@ end -- member object as a value. -- local function swim_pairs_next(ctx) - if ctx.swim.ptr == nil then + local s = ctx.swim + if s.ptr == nil then return swim_error_deleted() end local iterator = ctx.iterator local m = capi.swim_iterator_next(iterator) if m ~= nil then - m = swim_member_wrap(m) + m = swim_wrap_member(s, m) return m:uuid(), m end capi.swim_iterator_close(ffi.gc(iterator, nil)) @@ -732,6 +743,10 @@ local swim_not_configured_mt = { local swim_cfg_not_configured_mt = table.deepcopy(swim_cfg_mt) swim_cfg_not_configured_mt.__call = swim_cfg_first_call +-- Member cache stores week references so as to do not care about +-- removed members erasure - GC drops them automatically. +local cache_table_mt = { __mode = 'v' } + -- -- Create a new SWIM instance, and configure if @a cfg is -- provided. @@ -744,7 +759,8 @@ local function swim_new(cfg) ffi.gc(ptr, capi.swim_delete) local s = setmetatable({ ptr = ptr, - cfg = setmetatable({index = {}}, swim_cfg_not_configured_mt) + cfg = setmetatable({index = {}}, swim_cfg_not_configured_mt), + cache_table = setmetatable({}, cache_table_mt) }, swim_not_configured_mt) if cfg then local ok, err = s:cfg(cfg) diff --git a/test/swim/swim.result b/test/swim/swim.result index ef7203a37..531903e7f 100644 --- a/test/swim/swim.result +++ b/test/swim/swim.result @@ -930,6 +930,81 @@ s1:delete() s2:delete() --- ... +-- +-- Member table cache in Lua. +-- +s = swim.new({uuid = uuid(1), uri = uri()}) +--- +... +self = s:self() +--- +... +s:self() == self +--- +- true +... +s:add_member({uuid = uuid(2), uri = 1}) +--- +- true +... +s2 = s:member_by_uuid(uuid(2)) +--- +... +s2 +--- +- uri: 127.0.0.1:<port> + status: alive + incarnation: 0 + uuid: 00000000-0000-1000-8000-000000000002 + payload_size: 0 +... +-- Next lookups return the same member table. +s2 == s:member_by_uuid(uuid(2)) +--- +- true +... +s2_old_uri = s2:uri() +--- +... +-- Check, that it is impossible to take removed member from the +-- cached table. +s:remove_member(uuid(2)) +--- +- true +... +s:member_by_uuid(uuid(2)) +--- +- null +... +-- GC automatically removes members from the member table. +self = nil +--- +... +s2 = nil +--- +... +collectgarbage('collect') +--- +- 0 +... +s.cache_table +--- +- [] +... +s:add_member({uuid = uuid(2), uri = 2}) +--- +- true +... +s2 = s:member_by_uuid(uuid(2)) +--- +... +s2:uri() ~= s2_old_uri +--- +- true +... +s:delete() +--- +... test_run:cmd("clear filter") --- - true diff --git a/test/swim/swim.test.lua b/test/swim/swim.test.lua index c3387cf0a..3b0807f1e 100644 --- a/test/swim/swim.test.lua +++ b/test/swim/swim.test.lua @@ -307,4 +307,34 @@ s1_view:incarnation() s1:delete() s2:delete() +-- +-- Member table cache in Lua. +-- +s = swim.new({uuid = uuid(1), uri = uri()}) +self = s:self() +s:self() == self + +s:add_member({uuid = uuid(2), uri = 1}) +s2 = s:member_by_uuid(uuid(2)) +s2 +-- Next lookups return the same member table. +s2 == s:member_by_uuid(uuid(2)) +s2_old_uri = s2:uri() + +-- Check, that it is impossible to take removed member from the +-- cached table. +s:remove_member(uuid(2)) +s:member_by_uuid(uuid(2)) + +-- GC automatically removes members from the member table. +self = nil +s2 = nil +collectgarbage('collect') +s.cache_table +s:add_member({uuid = uuid(2), uri = 2}) +s2 = s:member_by_uuid(uuid(2)) +s2:uri() ~= s2_old_uri + +s:delete() + test_run:cmd("clear filter") -- 2.20.1 (Apple Git-117)
next prev parent reply other threads:[~2019-05-15 19:36 UTC|newest] Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-05-15 19:36 [tarantool-patches] [PATCH 00/10] swim Lua API Vladislav Shpilevoy 2019-05-15 19:36 ` [tarantool-patches] [PATCH 01/10] swim: fix an assertion on attempt to chage timeouts Vladislav Shpilevoy 2019-05-16 7:28 ` [tarantool-patches] " Konstantin Osipov 2019-05-15 19:36 ` Vladislav Shpilevoy [this message] 2019-05-16 7:31 ` [tarantool-patches] Re: [PATCH 10/10] swim: cache members in Lua member table Konstantin Osipov 2019-05-15 19:36 ` [tarantool-patches] [PATCH 02/10] swim: make swim_new_round() void Vladislav Shpilevoy 2019-05-16 7:31 ` [tarantool-patches] " Konstantin Osipov 2019-05-15 19:36 ` [tarantool-patches] [PATCH 03/10] swim: validate URI in swim_probe_member() Vladislav Shpilevoy 2019-05-16 7:31 ` [tarantool-patches] " Konstantin Osipov 2019-05-15 19:36 ` [tarantool-patches] [PATCH 04/10] swim: introduce Lua interface Vladislav Shpilevoy 2019-05-15 19:36 ` [tarantool-patches] [PATCH 05/10] swim: Lua bindings to manipulate member table Vladislav Shpilevoy 2019-05-16 7:32 ` [tarantool-patches] " Konstantin Osipov 2019-05-15 19:36 ` [tarantool-patches] [PATCH 06/10] swim: Lua bindings to access individual members Vladislav Shpilevoy 2019-05-15 19:36 ` [tarantool-patches] [PATCH 07/10] swim: pairs() function to iterate over member table Vladislav Shpilevoy 2019-05-15 19:36 ` [tarantool-patches] [PATCH 08/10] swim: allow to use cdata struct tt_uuid in Lua API Vladislav Shpilevoy 2019-05-15 19:36 ` [tarantool-patches] [PATCH 09/10] swim: cache decoded payload in the Lua module Vladislav Shpilevoy 2019-05-16 7:36 ` [tarantool-patches] " Konstantin Osipov 2019-05-16 11:58 ` Vladislav Shpilevoy 2019-05-16 22:46 ` Vladislav Shpilevoy 2019-05-21 16:57 ` [tarantool-patches] Re: [PATCH 00/10] swim Lua API Vladislav Shpilevoy
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=e71f7553b22ecdb6a442e83cb9c9f2ca379400a1.1557948687.git.v.shpilevoy@tarantool.org \ --to=v.shpilevoy@tarantool.org \ --cc=kostja@tarantool.org \ --cc=tarantool-patches@freelists.org \ --subject='Re: [tarantool-patches] [PATCH 10/10] swim: cache members in Lua member table' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox