You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2022/08/15 05:27:25 UTC

[apisix] branch master updated: fix: use a new way to manage clean_handler (#7648)

This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 768fc7cee fix: use a new way to manage clean_handler (#7648)
768fc7cee is described below

commit 768fc7ceed15e77041480365a7be783b62f4bfa6
Author: 罗泽轩 <sp...@gmail.com>
AuthorDate: Mon Aug 15 13:27:21 2022 +0800

    fix: use a new way to manage clean_handler (#7648)
---
 apisix/core/config_etcd.lua | 15 ++++-----------
 apisix/core/config_util.lua | 45 ++++++++++++++++++++++++++++++++++++++++-----
 apisix/core/config_xds.lua  |  8 ++------
 apisix/core/config_yaml.lua |  8 ++------
 t/core/config_util.t        | 39 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 87 insertions(+), 28 deletions(-)

diff --git a/apisix/core/config_etcd.lua b/apisix/core/config_etcd.lua
index edb05455c..85cf8d7f4 100644
--- a/apisix/core/config_etcd.lua
+++ b/apisix/core/config_etcd.lua
@@ -21,6 +21,7 @@
 
 local table        = require("apisix.core.table")
 local config_local = require("apisix.core.config_local")
+local config_util  = require("apisix.core.config_util")
 local log          = require("apisix.core.log")
 local json         = require("apisix.core.json")
 local etcd_apisix  = require("apisix.core.etcd")
@@ -314,12 +315,7 @@ local function sync_data(self)
 
         if self.values then
             for i, val in ipairs(self.values) do
-                if val and val.clean_handlers then
-                    for _, clean_handler in ipairs(val.clean_handlers) do
-                        clean_handler(val)
-                    end
-                    val.clean_handlers = nil
-                end
+                config_util.fire_all_clean_handlers(val)
             end
 
             self.values = nil
@@ -406,11 +402,8 @@ local function sync_data(self)
         local pre_index = self.values_hash[key]
         if pre_index then
             local pre_val = self.values[pre_index]
-            if pre_val and pre_val.clean_handlers then
-                for _, clean_handler in ipairs(pre_val.clean_handlers) do
-                    clean_handler(pre_val)
-                end
-                pre_val.clean_handlers = nil
+            if pre_val then
+                config_util.fire_all_clean_handlers(pre_val)
             end
 
             if res.value then
diff --git a/apisix/core/config_util.lua b/apisix/core/config_util.lua
index 8a2ce7b57..b3fb13b7c 100644
--- a/apisix/core/config_util.lua
+++ b/apisix/core/config_util.lua
@@ -20,8 +20,10 @@
 -- @module core.config_util
 
 local core_tab = require("apisix.core.table")
+local log = require("apisix.core.log")
 local str_byte = string.byte
 local str_char = string.char
+local ipairs = ipairs
 local setmetatable = setmetatable
 local tostring = tostring
 local type = type
@@ -56,23 +58,56 @@ end
 -- or cancelled. Note that Nginx worker exit doesn't trigger the clean handler.
 -- Return an index so that we can cancel it later.
 function _M.add_clean_handler(item, func)
-    local idx = #item.clean_handlers + 1
-    item.clean_handlers[idx] = func
-    return idx
+    if not item.clean_handlers._id then
+        item.clean_handlers._id = 1
+    end
+
+    local id = item.clean_handlers._id
+    item.clean_handlers._id = item.clean_handlers._id + 1
+    core_tab.insert(item.clean_handlers, {f = func, id = id})
+    return id
 end
 
 
 -- cancel a clean handler added by add_clean_handler.
 -- If `fire` is true, call the clean handler.
 function _M.cancel_clean_handler(item, idx, fire)
-    local f = item.clean_handlers[idx]
-    core_tab.remove(item.clean_handlers, idx)
+    local pos, f
+    -- the number of pending clean handler is small so we can cancel them in O(n)
+    for i, clean_handler in ipairs(item.clean_handlers) do
+        if clean_handler.id == idx then
+            pos = i
+            f = clean_handler.f
+            break
+        end
+    end
+
+    if not pos then
+        log.error("failed to find clean_handler with idx ", idx)
+        return
+    end
+
+    core_tab.remove(item.clean_handlers, pos)
     if fire then
         f(item)
     end
 end
 
 
+-- fire all clean handlers added by add_clean_handler.
+function _M.fire_all_clean_handlers(item)
+    if not item.clean_handlers then
+        return
+    end
+
+    for _, clean_handler in ipairs(item.clean_handlers) do
+        clean_handler.f(item)
+    end
+
+    item.clean_handlers = nil
+end
+
+
 ---
 -- Convert different time units to seconds as time units.
 -- Time intervals can be specified in milliseconds, seconds, minutes, hours, days and so on,
diff --git a/apisix/core/config_xds.lua b/apisix/core/config_xds.lua
index 793592b6f..bdb45206a 100644
--- a/apisix/core/config_xds.lua
+++ b/apisix/core/config_xds.lua
@@ -20,6 +20,7 @@
 -- @module core.config_xds
 
 local config_local      = require("apisix.core.config_local")
+local config_util       = require("apisix.core.config_util")
 local string            = require("apisix.core.string")
 local log               = require("apisix.core.log")
 local json              = require("apisix.core.json")
@@ -151,12 +152,7 @@ local function sync_data(self)
 
     if self.values then
         for _, val in ipairs(self.values) do
-            if val and val.clean_handlers then
-                for _, clean_handler in ipairs(val.clean_handlers) do
-                    clean_handler(val)
-                end
-                val.clean_handlers = nil
-            end
+            config_util.fire_all_clean_handlers(val)
         end
         self.values = nil
         self.values_hash = nil
diff --git a/apisix/core/config_yaml.lua b/apisix/core/config_yaml.lua
index 24a5ff57a..0c6564caf 100644
--- a/apisix/core/config_yaml.lua
+++ b/apisix/core/config_yaml.lua
@@ -20,6 +20,7 @@
 -- @module core.config_yaml
 
 local config_local = require("apisix.core.config_local")
+local config_util  = require("apisix.core.config_util")
 local yaml         = require("tinyyaml")
 local log          = require("apisix.core.log")
 local json         = require("apisix.core.json")
@@ -142,12 +143,7 @@ local function sync_data(self)
 
     if self.values then
         for _, item in ipairs(self.values) do
-            if item.clean_handlers then
-                for _, clean_handler in ipairs(item.clean_handlers) do
-                    clean_handler(item)
-                end
-                item.clean_handlers = nil
-            end
+            config_util.fire_all_clean_handlers(item)
         end
         self.values = nil
     end
diff --git a/t/core/config_util.t b/t/core/config_util.t
index 80f01a5d2..2b012fc97 100644
--- a/t/core/config_util.t
+++ b/t/core/config_util.t
@@ -70,3 +70,42 @@ __DATA__
             end
         }
     }
+
+
+
+=== TEST 2: add_clean_handler / cancel_clean_handler / fire_all_clean_handlers
+--- config
+    location /t {
+        content_by_lua_block {
+            local util = require("apisix.core.config_util")
+            local function setup()
+                local item = {clean_handlers = {}}
+                local idx1 = util.add_clean_handler(item, function()
+                    ngx.log(ngx.WARN, "fire one")
+                end)
+                local idx2 = util.add_clean_handler(item, function()
+                    ngx.log(ngx.WARN, "fire two")
+                end)
+                return item, idx1, idx2
+            end
+
+            local item, idx1, idx2 = setup()
+            util.cancel_clean_handler(item, idx1, true)
+            util.cancel_clean_handler(item, idx2, true)
+
+            local item, idx1, idx2 = setup()
+            util.fire_all_clean_handlers(item)
+
+            local item, idx1, idx2 = setup()
+            util.cancel_clean_handler(item, idx2)
+            util.fire_all_clean_handlers(item)
+
+            local item, idx1, idx2 = setup()
+            util.cancel_clean_handler(item, idx1)
+            util.fire_all_clean_handlers(item)
+        }
+    }
+--- grep_error_log eval
+qr/fire \w+/
+--- grep_error_log_out eval
+"fire one\nfire two\n" x 3