Skip to content

Commit ca6df0f

Browse files
authored
Merge pull request #1583 from tkan145/batcher-refactor
perf(3scale_batcher): replace regex with string operations
2 parents 4942172 + 0b6b299 commit ca6df0f

5 files changed

Lines changed: 106 additions & 45 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1212
- Logging Policy: construct all templates at init time [PR #1587](https://github.com/3scale/APIcast/pull/1587)
1313
- Routing Policy: eliminate unnecessary TemplateString allocation per request [PR #1585](https://github.com/3scale/APIcast/pull/1585)
1414
- Headers Policy: don't render template string when delete header [PR #1586](https://github.com/3scale/APIcast/pull/1586)
15+
- 3scale Batcher Policy: replace regex with string operations [PR #1583](https://github.com/3scale/APIcast/pull/1583)
1516

1617
### Fixed
1718
- Correct FAPI header to `x-fapi-interaction-id` [PR #1557](https://github.com/3scale/APIcast/pull/1557) [THREESCALE-11957](https://issues.redhat.com/browse/THREESCALE-11957)

gateway/src/apicast/policy/3scale_batcher/3scale_batcher.lua

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,11 @@ local function handle_backend_error(self, service, transaction, cache_handler)
151151
end
152152
end
153153

154-
local function handle_cached_auth(self, cached_auth, service, transaction)
155-
if cached_auth.status == 200 then
154+
local function handle_cached_auth(self, cached_status, rejection_reason, service, transaction)
155+
if cached_status == 200 then
156156
self.reports_batcher:add(transaction)
157157
else
158-
return error(service, cached_auth.rejection_reason)
158+
return error(service, rejection_reason)
159159
end
160160
end
161161

@@ -197,13 +197,13 @@ function _M:access(context)
197197

198198
ensure_timer_task_created(self, service_id, backend)
199199

200-
local cached_auth = self.auths_cache:get(transaction)
201-
local auth_is_cached = (cached_auth and true) or false
200+
local cached_status, rejection_reason = self.auths_cache:get(transaction)
201+
local auth_is_cached = cached_status ~= nil
202202
metrics.update_cache_counters(auth_is_cached)
203203

204204

205-
if cached_auth then
206-
handle_cached_auth(self, cached_auth, service, transaction)
205+
if cached_status then
206+
return handle_cached_auth(self, cached_status, rejection_reason, service, transaction)
207207
else
208208
local formatted_usage = usage:format()
209209
local backend_res = backend:authorize(formatted_usage, credentials)
@@ -218,12 +218,12 @@ function _M:access(context)
218218
end
219219

220220
if backend_status == 200 then
221-
handle_backend_ok(self, transaction)
221+
return handle_backend_ok(self, transaction)
222222
elseif backend_status >= 400 and backend_status < 500 then
223-
handle_backend_denied(
223+
return handle_backend_denied(
224224
self, service, transaction, backend_status, backend_res.headers)
225225
else
226-
handle_backend_error(self, service, transaction, cache_handler)
226+
return handle_backend_error(self, service, transaction, cache_handler)
227227
end
228228
end
229229
end

gateway/src/apicast/policy/3scale_batcher/auths_cache.lua

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
local keys_helper = require('apicast.policy.3scale_batcher.keys_helper')
22

3-
local re = require('ngx.re')
4-
local re_split = re.split
3+
local str_find = string.find
4+
local str_sub = string.sub
55

66
local setmetatable = setmetatable
77
local format = string.format
@@ -39,8 +39,13 @@ function _M:get(transaction)
3939

4040
if not cached_value then return nil end
4141

42-
local split_val = re_split(cached_value, ':', 'oj', nil, 2)
43-
return { status = tonumber(split_val[1]), rejection_reason = split_val[2] }
42+
local colon = str_find(cached_value, ':', 1, true)
43+
if colon then
44+
return tonumber(str_sub(cached_value, 1, colon - 1)),
45+
str_sub(cached_value, colon + 1)
46+
end
47+
48+
return tonumber(cached_value)
4449
end
4550

4651
--- Store an authorization in the cache.

gateway/src/apicast/policy/3scale_batcher/keys_helper.lua

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
local ipairs = ipairs
22
local format = string.format
3+
local str_find = string.find
34
local insert = table.insert
45
local concat = table.concat
56
local sort = table.sort
@@ -39,12 +40,25 @@ local function metrics_part_in_key(usage)
3940
end
4041

4142
local regexes_report_key = {
42-
[[service_id:(?<service_id>[\w-]+),user_key:(?<user_key>[\S-]+),metric:(?<metric>[\S-]+)]],
43-
[[service_id:(?<service_id>[\w-]+),access_token:(?<access_token>[\S-]+),metric:(?<metric>[\S-]+)]],
44-
[[service_id:(?<service_id>[\w-]+),app_id:(?<app_id>[\S-]+),app_key:(?<app_key>[\S-]+),metric:(?<metric>[\S-]+)]],
45-
[[service_id:(?<service_id>[\w-]+),app_id:(?<app_id>[\S-]+),metric:(?<metric>[\S-]+)]],
43+
user_key= [[service_id:(?<service_id>[\w-]+),user_key:(?<user_key>[\S-]+),metric:(?<metric>[\S-]+)]],
44+
access_token = [[service_id:(?<service_id>[\w-]+),access_token:(?<access_token>[\S-]+),metric:(?<metric>[\S-]+)]],
45+
app_key = [[service_id:(?<service_id>[\w-]+),app_id:(?<app_id>[\S-]+),app_key:(?<app_key>[\S-]+),metric:(?<metric>[\S-]+)]],
46+
app_id = [[service_id:(?<service_id>[\w-]+),app_id:(?<app_id>[\S-]+),metric:(?<metric>[\S-]+)]],
4647
}
4748

49+
50+
local function detect_cred_type(key)
51+
if str_find(key, 'user_key:', 1, true) then
52+
return 'user_key'
53+
elseif str_find(key, 'access_token:', 1, true) then
54+
return 'access_token'
55+
elseif str_find(key, 'app_key:', 1, true) then
56+
return 'app_key'
57+
elseif str_find(key, 'app_id:', 1, true) then
58+
return 'app_id'
59+
end
60+
end
61+
4862
function _M.key_for_cached_auth(transaction)
4963
local service_part = format("service_id:%s", transaction.service_id)
5064
local creds_part = creds_part_in_key(transaction.credentials)
@@ -61,24 +75,26 @@ function _M.key_for_batched_report(service_id, credentials, metric_name)
6175
end
6276

6377
function _M.report_from_key_batched_report(key, value)
64-
for _, regex in ipairs(regexes_report_key) do
65-
local match = ngx_re.match(key, regex, 'oj')
66-
67-
if match then
68-
-- some credentials will be nil.
69-
return {
70-
service_id = match.service_id,
71-
metric = match.metric,
72-
user_key = match.user_key,
73-
access_token = match.access_token,
74-
app_id = match.app_id,
75-
app_key = match.app_key,
76-
value = value
77-
}
78-
end
78+
local cred_type = detect_cred_type(key)
79+
if not cred_type then
80+
return nil, 'credentials not found'
81+
end
82+
83+
local match = ngx_re.match(key, regexes_report_key[cred_type], 'oj')
84+
if match then
85+
-- some credentials will be nil.
86+
return {
87+
service_id = match.service_id,
88+
metric = match.metric,
89+
user_key = match.user_key,
90+
access_token = match.access_token,
91+
app_id = match.app_id,
92+
app_key = match.app_key,
93+
value = value
94+
}
7995
end
8096

81-
return nil, 'credentials not found'
97+
return nil, "credentials not found"
8298
end
8399

84100
return _M

spec/policy/3scale_batcher/auths_cache_spec.lua

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ describe('Auths cache', function()
2525

2626
cache:set(transaction, auth_status)
2727

28-
local cached = cache:get(transaction)
29-
assert.equals(auth_status, cached.status)
28+
local cached_status = cache:get(transaction)
29+
assert.equals(auth_status, cached_status)
3030
end)
3131

3232
it('caches auth with app id + app key', function()
@@ -35,8 +35,8 @@ describe('Auths cache', function()
3535

3636
cache:set(transaction, auth_status)
3737

38-
local cached = cache:get(transaction)
39-
assert.equals(auth_status, cached.status)
38+
local cached_status = cache:get(transaction)
39+
assert.equals(auth_status, cached_status)
4040
end)
4141

4242
it('caches auth with access token', function()
@@ -45,8 +45,8 @@ describe('Auths cache', function()
4545

4646
cache:set(transaction, auth_status)
4747

48-
local cached = cache:get(transaction)
49-
assert.equals(auth_status, cached.status)
48+
local cached_status = cache:get(transaction)
49+
assert.equals(auth_status, cached_status)
5050
end)
5151

5252
it('caches auths with same usages but different order in the same key', function()
@@ -65,8 +65,8 @@ describe('Auths cache', function()
6565

6666
cache:set(transaction_with_order_1, auth_status)
6767

68-
local cached = cache:get(transaction_with_order_2)
69-
assert.equals(auth_status, cached.status)
68+
local cached_status = cache:get(transaction_with_order_2)
69+
assert.equals(auth_status, cached_status)
7070
end)
7171

7272
it('caches a rejection reason when given', function()
@@ -77,15 +77,54 @@ describe('Auths cache', function()
7777

7878
cache:set(transaction, not_authorized_status, rejection_reason)
7979

80-
local cached = cache:get(transaction)
81-
assert.equals(not_authorized_status, cached.status)
82-
assert.equals(rejection_reason, cached.rejection_reason)
80+
local cached_status, cached_rejection_reason = cache:get(transaction)
81+
assert.equals(not_authorized_status, cached_status)
82+
assert.equals(rejection_reason, cached_rejection_reason)
8383
end)
8484

8585
it('returns nil when something is not cached', function()
8686
local user_key = { user_key = 'uk' }
8787
local transaction = Transaction.new(service_id, user_key, usage)
88+
8889

8990
assert.is_nil(cache:get(transaction))
9091
end)
92+
93+
it('returns status without rejection_reason when cached without one', function()
94+
local user_key = { user_key = 'uk' }
95+
local transaction = Transaction.new(service_id, user_key, usage)
96+
97+
cache:set(transaction, auth_status)
98+
99+
local cached_status, cached_rejection_reason = cache:get(transaction)
100+
assert.equals(auth_status, cached_status)
101+
assert.is_nil(cached_rejection_reason)
102+
end)
103+
104+
it('parses rejection reason containing colons', function()
105+
local app_id_and_key = { app_id = 'an_id', app_key = 'a_key' }
106+
local transaction = Transaction.new(service_id, app_id_and_key, usage)
107+
local rejection_reason = 'reason:with:colons'
108+
109+
cache:set(transaction, 409, rejection_reason)
110+
111+
local cached_status, cached_rejection_reason = cache:get(transaction)
112+
assert.equals(409, cached_status)
113+
assert.equals(rejection_reason, cached_rejection_reason)
114+
end)
115+
116+
it('returns correct status for different HTTP status codes', function()
117+
local user_key = { user_key = 'uk' }
118+
119+
for _, status_code in ipairs({ 200, 403, 404, 409, 500 }) do
120+
local tx_usage = Usage.new()
121+
tx_usage:add('m_' .. status_code, 1)
122+
local transaction = Transaction.new(service_id, user_key, tx_usage)
123+
124+
cache:set(transaction, status_code)
125+
126+
local cached_status, cached_rejection_reason = cache:get(transaction)
127+
assert.equals(status_code, cached_status)
128+
end
129+
end)
91130
end)

0 commit comments

Comments
 (0)