Tarantool development patches archive
 help / color / mirror / Atom feed
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)

  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