From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 9063A2E835 for ; Wed, 15 May 2019 15:36:49 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FiLpSi-0ePKV for ; Wed, 15 May 2019 15:36:49 -0400 (EDT) Received: from smtpng1.m.smailru.net (smtpng1.m.smailru.net [94.100.181.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 45BC22EC6A for ; Wed, 15 May 2019 15:36:49 -0400 (EDT) From: Vladislav Shpilevoy Subject: [tarantool-patches] [PATCH 10/10] swim: cache members in Lua member table Date: Wed, 15 May 2019 22:36:38 +0300 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-Help: List-Unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-Subscribe: List-Owner: List-post: List-Archive: To: tarantool-patches@freelists.org Cc: kostja@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: + 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)