Skip to content
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

[policy] run __gc metamethod when policies are garbage collected #688

Merged
merged 3 commits into from
Jun 29, 2018

Conversation

mikz
Copy link
Contributor

@mikz mikz commented May 1, 2018

This would allow doing cleanup when policies are reloaded by changed configuration (like shutting down timers).

end

local function metatable(policy)
local proxy = newproxy(true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I learnt about newproxy while reviewing this PR.

If I understood it correctly we need to do this to include __gc in the table. It looks like this is not needed in Lua 5.2+ and will not be needed in future versions of LuaJIT: LuaJIT/LuaJIT#47

I think this merits a comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It definitely needs plenty of comments.

I seriously doubt it will land in LuaJIT because it depends on LuaJIT/LuaJIT#38. Even though LuaJIT/LuaJIT#47 is closed it is not implemented.

Another approach is to use void pointer from ffi and use ffi.gc like:

local ffi = require('ffi')
local p = ffi.new('void *')
 ffi.gc(p, function() print('__gc') end)
collectgarbage()
p = nil
collectgarbage()

@@ -219,6 +219,8 @@ function lazy.rewrite(configuration, host)
ngx.log(ngx.WARN, 'failed to acquire lock to lazy load: ', host, ' error: ', err)
end

collectgarbage()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some configurations when reloading, this line is not executed. I think we need to call collectgarbage also in refresh_configuration, or somewhere else that runs when re-loading in 'boot' mode.

Copy link
Contributor

@davidor davidor Jun 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed a commit that fixes this.

@mikz mikz requested a review from a team as a code owner June 27, 2018 15:05
local cjson = require('cjson')

local tonumber = tonumber
local new = _M.new

function mt.__gc(policy)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused argument 'policy'

return setmetatable({}, mt)
local p = setmetatable({}, mt)

p.gc = GC.delegate(p)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why assign to .gc ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They have both pointer to the other, so their life is tied together.
When the gc object is GC'd it will call the __gc method on the policy metatable.

Using the userdata as proxy had significant performance issue in my early benchmarks, but can't reproduce it now, so they might have been invalid.

There are several other issues with the delegation on policies: calling next or type. Those are used by inspect and by some our code as well. We would have to patch next and type methods to rely on some other metamethods.

I agree this is less than ideal and will explore the approach of allocating metatable per policy instance, so it can be GCd with the policy.

@@ -39,7 +39,7 @@ local name = env.value('APICAST_MODULE') or 'apicast.policy.apicast'
local ok, mod = prequire(name)

if ok and mod then
if type(mod) == 'table' then
if type(mod) == 'table' or true then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is always true.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know. Needed to do this temporarily because type(mod) returns userdata.

@@ -18,7 +18,8 @@ local PHASES = {
'ssl_certificate',
}

local setmetatable = setmetatable
local GC = require('apicast.gc')
local setmetatable = GC.setmetatable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should rename this var to avoid confusion.
When I read this diff for the first time I assumed that we were using the normal setmetatable function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

__gc = function(self)
local mt = getmetatable(self.table)

if mt and mt.__gc then return mt.__gc(table) end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be self.table.

mt.__gc = spy.new(function(p) property = p.someproperty end)
local policy = MyPolicy.new()
policy.someproperty = 'foobar'
policy = nil
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value assigned to variable 'policy' is unused

local MyPolicy, mt = policy.new('my_policy', '1.0')
local property
mt.__gc = spy.new(function(p) property = p.someproperty end)
local policy = MyPolicy.new()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shadowing upvalue 'policy' on line 1

@@ -3,7 +3,7 @@
-- Also can interrupt the execution and skip the current phase or
-- the whole processing of the request.

local _M = require('apicast.policy').new('Echo Policy')
local _M, mt = require('apicast.policy').new('Echo Policy')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused variable 'mt'

@mikz mikz changed the title [wip] prototype of running __gc metamethod on policies [policy] run __gc metamethod when policies are garbage collected Jun 28, 2018
@mikz
Copy link
Contributor Author

mikz commented Jun 28, 2018

@davidor sorry for rebasing your commits, but I think it is better when the relevant changes (code, tests) are in one commit and I needed to make a change anyway to cover the self.table issue.

@davidor
Copy link
Contributor

davidor commented Jun 28, 2018

@mikz No worries, I agree with that approach.

When policy is reloaded it is GC'd and gets __gc metamethod called.
That can be used for example for unregistering timers.
@davidor davidor merged commit 0fa2ed4 into master Jun 29, 2018
@davidor davidor deleted the policy-gc branch June 29, 2018 08:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants