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

feat(request-aware-table) add request aware table #11017

Merged
merged 9 commits into from
Oct 12, 2023
Merged

Conversation

samugi
Copy link
Member

@samugi samugi commented Jun 6, 2023

Summary

Add a request-aware table able to detect accesses from different requests.

Checklist

Issue reference

KAG-1570

@samugi samugi marked this pull request as draft June 6, 2023 16:27
@samugi samugi force-pushed the feat/request-aware-table branch 2 times, most recently from 35086ad to 95706cd Compare June 6, 2023 17:38
@bungle
Copy link
Member

bungle commented Jun 7, 2023

What is request aware table in comparison to ngx.ctx or kong.ctx.plugin|shared?

@samugi
Copy link
Member Author

samugi commented Jun 7, 2023

What is request aware table in comparison to ngx.ctx or kong.ctx.plugin|shared?

I wondered that myself @bungle, thanks for bringing it up.

The main difference is that this table can detect race conditions and throw an error if they happen, instead of using separate scopes for each request to prevent them.
Race condition checks (which currently require an access to ngx.var per request) would only be turned on during testing, to ensure the table is used properly (i.e. cleared before it's accessed by another request). This allows defining a table that is local to the module where it is instantiated, can be cleared at will, and does not rely on a shared context.

However, if the performance impact of accessing this table compared to using the context is not significant, we could solve the same problem just as in this PR, using kong.ctx.plugin to prevent race conditions in the first place.

I'd be curious to hear @dndx 's opinion as well

@samugi samugi force-pushed the feat/request-aware-table branch 3 times, most recently from 0db9d43 to 7530d1d Compare June 8, 2023 18:12
kong/tools/request_aware_table.lua Outdated Show resolved Hide resolved
kong/tools/request_aware_table.lua Outdated Show resolved Hide resolved
@samugi samugi marked this pull request as ready for review August 31, 2023 10:23
@samugi samugi force-pushed the feat/request-aware-table branch 5 times, most recently from 85553b9 to 862d76d Compare September 8, 2023 07:30
@samugi samugi force-pushed the feat/request-aware-table branch 2 times, most recently from 6f69d98 to d83b6d3 Compare September 12, 2023 14:29
@AndyZhang0707
Copy link
Collaborator

@dndx could you take a look at this PR again? thx

kong/tools/request_aware_table.lua Outdated Show resolved Hide resolved
@samugi samugi force-pushed the feat/request-aware-table branch 2 times, most recently from ddf396f to fede892 Compare September 25, 2023 16:40
kong/tools/request_aware_table.lua Outdated Show resolved Hide resolved

-- Check if access is allowed for table, based on the request ID
local function enforce_sequential_access(table)
if next(table.__data) == nil or not get_request() then
Copy link
Member

Choose a reason for hiding this comment

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

Do we need the empty __data table check? I thought just checking __allowed_request_id below is enough.

Copy link
Member Author

@samugi samugi Sep 27, 2023

Choose a reason for hiding this comment

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

the empty __data check is used to reset __allowed_request_id when the table is cleared. If there is no data it means the table was emptied. I removed it now that I reintroduced the :clear() method

Copy link
Member

Choose a reason for hiding this comment

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

@samugi I see. :clear would be a safer approach and I think we should keep that. It also makes the clearing intention more explicit.

end

return {
new = new,
Copy link
Member

@dndx dndx Sep 26, 2023

Choose a reason for hiding this comment

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

Do we need a :clear method as well? How to clear __data?

Copy link
Member Author

@samugi samugi Sep 27, 2023

Choose a reason for hiding this comment

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

I initially included a :clear method but that would mean the table has a different interface when in debug_mode compared to when it is not (in which case we just return a regular table).

One alternative I implemented now is to always include the :clear method for request_aware_table, the difference being that in non debug_mode the metatable with concurrency checks is not applied, wdyt?

Copy link
Member

Choose a reason for hiding this comment

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

I see what you are saying. We can do this:

With debug mode on:
Use the proxy and metatable.

With debug mode on:
Use a different metatable _mt_direct, no proxy in this case. Define the :clear on this metatable only, not table instance.

This avoids you having to hack the "clear" method on the table each time, and prevents it being accidentally cleared by the user using table.clear manually.

Copy link
Member Author

Choose a reason for hiding this comment

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

ok, I like that.

@samugi samugi force-pushed the feat/request-aware-table branch 3 times, most recently from e5e3d6a to 385dffb Compare September 27, 2023 10:55
Copy link
Member Author

Choose a reason for hiding this comment

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

usage in a plugin

[cache_key] = <integer>
--]]
}
local cur_usage = request_aware_table.new()
Copy link
Member Author

Choose a reason for hiding this comment

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

we might want to preallocate some nrec, what could be a good value?

Copy link
Contributor

@nowNick nowNick left a comment

Choose a reason for hiding this comment

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

Nice work! A clever idea and neat implementation 🚀

I left a few code style comments but it's entirely up to you. I'm happy with the way the code looks right now 👏

samugi and others added 9 commits October 11, 2023 22:43
add a request-aware table able to detect accesses from different
requests.
* refactor
* only use static log level to turn concurrency checks on or off
* use single metatable, keep data and request_id in the instance
* use table.new -style initialization
* reintroduce :clear() method

Co-authored-by: Datong Sun <datong.sun@konghq.com>
* small refactors here and there
@dndx dndx merged commit 39a545d into master Oct 12, 2023
23 checks passed
@dndx dndx deleted the feat/request-aware-table branch October 12, 2023 04:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants