Skip to content

Commit 433af69

Browse files
committed
Added atomic type opperations to shmdict
- Added cas(compare and swap) to shdict - Added get_if_not_eq to shdict ihanged from cog to get_if_not_eq
1 parent ddd9290 commit 433af69

File tree

1 file changed

+259
-2
lines changed

1 file changed

+259
-2
lines changed

lib/resty/core/shdict.lua

Lines changed: 259 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ local ngx_lua_ffi_shdict_set_expire
4040
local ngx_lua_ffi_shdict_capacity
4141
local ngx_lua_ffi_shdict_free_space
4242
local ngx_lua_ffi_shdict_udata_to_zone
43-
43+
local ngx_lua_ffi_shdict_cas
44+
local ngx_lua_ffi_shdict_get_if_not_eq
4445

4546
if subsystem == 'http' then
4647
ffi.cdef[[
@@ -70,6 +71,20 @@ int ngx_http_lua_ffi_shdict_set_expire(void *zone,
7071
size_t ngx_http_lua_ffi_shdict_capacity(void *zone);
7172

7273
void *ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata);
74+
75+
int ngx_http_lua_ffi_shdict_cas(void *zone, const unsigned char *key,
76+
size_t key_len, int old_value_type, const unsigned char *old_str_value_buf,
77+
size_t old_str_value_len, double old_num_value, int old_user_flags,
78+
int value_type, const unsigned char *str_value_buf, size_t str_value_len,
79+
double num_value, int user_flags, int set_user_flags,
80+
long exptime, int match_flags, int *match, char **errmsg, int *forcible);
81+
int
82+
ngx_http_lua_ffi_shdict_get_if_not_eq(void *zone,
83+
const unsigned char *key, size_t key_len, int old_value_type,
84+
const unsigned char *old_str_value_buf, size_t old_str_value_len,
85+
double old_num_value, int old_user_flags, int *value_type,
86+
unsigned char **str_value_buf, size_t *str_value_len, double *num_value,
87+
int *user_flags, int match_flags, int *match, char **errmsg);
7388
]]
7489

7590
ngx_lua_ffi_shdict_get = C.ngx_http_lua_ffi_shdict_get
@@ -81,7 +96,8 @@ void *ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata);
8196
ngx_lua_ffi_shdict_capacity = C.ngx_http_lua_ffi_shdict_capacity
8297
ngx_lua_ffi_shdict_udata_to_zone =
8398
C.ngx_http_lua_ffi_shdict_udata_to_zone
84-
99+
ngx_lua_ffi_shdict_cas = C.ngx_http_lua_ffi_shdict_cas
100+
ngx_lua_ffi_shdict_get_if_not_eq = C.ngx_http_lua_ffi_shdict_get_if_not_eq
85101
if not pcall(function ()
86102
return C.ngx_http_lua_ffi_shdict_free_space
87103
end)
@@ -124,6 +140,20 @@ int ngx_stream_lua_ffi_shdict_set_expire(void *zone,
124140
size_t ngx_stream_lua_ffi_shdict_capacity(void *zone);
125141

126142
void *ngx_stream_lua_ffi_shdict_udata_to_zone(void *zone_udata);
143+
144+
int ngx_stream_lua_ffi_shdict_cas(void *zone, const unsigned char *key,
145+
size_t key_len, int old_value_type, const unsigned char *old_str_value_buf,
146+
size_t old_str_value_len, double old_num_value, int old_user_flags,
147+
int value_type, const unsigned char *str_value_buf, size_t str_value_len,
148+
double num_value, int user_flags, int set_user_flags,
149+
long exptime, int match_flags, int *match, char **errmsg, int *forcible);
150+
int
151+
ngx_stream_lua_ffi_shdict_get_if_not_eq(void *zone,
152+
const unsigned char *key, size_t key_len, int old_value_type,
153+
const unsigned char *old_str_value_buf, size_t old_str_value_len,
154+
double old_num_value, int old_user_flags, int *value_type,
155+
unsigned char **str_value_buf, size_t *str_value_len, double *num_value,
156+
int *user_flags, int match_flags, int *match, char **errmsg);
127157
]]
128158

129159
ngx_lua_ffi_shdict_get = C.ngx_stream_lua_ffi_shdict_get
@@ -135,6 +165,8 @@ void *ngx_stream_lua_ffi_shdict_udata_to_zone(void *zone_udata);
135165
ngx_lua_ffi_shdict_capacity = C.ngx_stream_lua_ffi_shdict_capacity
136166
ngx_lua_ffi_shdict_udata_to_zone =
137167
C.ngx_stream_lua_ffi_shdict_udata_to_zone
168+
ngx_lua_ffi_shdict_cas = C.ngx_stream_lua_ffi_shdict_cas
169+
ngx_lua_ffi_shdict_get_if_not_eq = C.ngx_stream_lua_ffi_shdict_get_if_not_eq
138170

139171
if not pcall(function ()
140172
return C.ngx_stream_lua_ffi_shdict_free_space
@@ -164,6 +196,7 @@ local value_type = ffi_new("int[1]")
164196
local user_flags = ffi_new("int[1]")
165197
local num_value = ffi_new("double[1]")
166198
local is_stale = ffi_new("int[1]")
199+
local match = ffi_new("int[1]")
167200
local forcible = ffi_new("int[1]")
168201
local str_value_buf = ffi_new("unsigned char *[1]")
169202
local errmsg = base.get_errmsg_ptr()
@@ -291,6 +324,228 @@ local function shdict_delete(zone, key)
291324
return shdict_set(zone, key, nil)
292325
end
293326

327+
local function shdict_cas(zone, key, old_value, old_flags,
328+
value, flags, exptime)
329+
zone = check_zone(zone)
330+
331+
if not exptime then
332+
exptime = 0
333+
elseif exptime < 0 then
334+
error('bad "exptime" argument',2)
335+
end
336+
337+
if key == nil then
338+
return nil, "nil key"
339+
end
340+
341+
if type(key) ~= "string" then
342+
key = tostring(key)
343+
end
344+
345+
local key_len = #key
346+
if key_len == 0 then
347+
return nil, "empty key"
348+
end
349+
if key_len > 65535 then
350+
return nil, "key to long"
351+
end
352+
353+
local set_user_flags = 1
354+
if not flags then
355+
set_user_flags = 0
356+
flags = 0
357+
end
358+
359+
local match_flags = 1
360+
if not old_flags then
361+
old_flags = 0
362+
match_flags = 0
363+
end
364+
365+
local str_val_buf
366+
local str_val_len = 0
367+
local num_val = 0
368+
local valtyp = type(value)
369+
370+
if valtyp == "string" then
371+
valtyp = 4 -- LUA_TSTRING
372+
str_val_buf = value
373+
str_val_len = #value
374+
375+
elseif valtyp == "number" then
376+
valtyp = 3 -- LUA_TNUMBER
377+
num_val = value
378+
379+
elseif value == nil then
380+
valtyp = 0 -- LUA_TNIL
381+
382+
elseif valtyp == "boolean" then
383+
valtyp = 1 -- LUA_TBOOLEAN
384+
num_val = value and 1 or 0
385+
386+
else
387+
return nil, "bad value type"
388+
end
389+
390+
local old_str_val_buf
391+
local old_str_val_len = 0
392+
local old_num_val = 0
393+
local old_valtyp = type(old_value)
394+
395+
if old_valtyp == "string" then
396+
old_valtyp = 4 -- LUA_TSTRING
397+
old_str_val_buf = old_value
398+
old_str_val_len = #old_value
399+
400+
elseif old_valtyp == "number" then
401+
old_valtyp = 3 -- LUA_TNUMBER
402+
old_num_val = old_value
403+
404+
elseif old_value == nil then
405+
old_valtyp = 0 -- LUA_TNIL
406+
407+
elseif old_valtyp == "boolean" then
408+
old_valtyp = 1 -- LUA_TBOOLEAN
409+
old_num_val = old_value and 1 or 0
410+
411+
else
412+
return nil, "bad old_value type"
413+
end
414+
local rc = ngx_lua_ffi_shdict_cas(zone, key, key_len,
415+
old_valtyp, old_str_val_buf,
416+
old_str_val_len, old_num_val,
417+
old_flags,
418+
valtyp, str_val_buf,
419+
str_val_len, num_val, flags,
420+
set_user_flags,
421+
exptime * 1000,
422+
match_flags, match,
423+
errmsg, forcible)
424+
if rc == 0 then -- NGX_OK
425+
return true, nil, forcible[0] == 1
426+
end
427+
428+
-- NGX_DECLINED or NGX_ERROR
429+
if match[0] == 1 then
430+
return false, false, forcible[0] == 1
431+
end
432+
if errmsg[0] ~= nil then
433+
return false, ffi_str(errmsg[0]), forcible[0] == 1
434+
end
435+
error("errmsg not specified")
436+
437+
end
438+
local function shdict_get_if_not_eq(zone, key, old_value, old_flags)
439+
zone = check_zone(zone)
440+
441+
if key == nil then
442+
return nil, "nil key"
443+
end
444+
445+
if type(key) ~= "string" then
446+
key = tostring(key)
447+
end
448+
449+
local match_flags = 1
450+
if not old_flags then
451+
old_flags = 0
452+
match_flags = 0
453+
end
454+
455+
local key_len = #key
456+
if key_len == 0 then
457+
return nil, "empty key"
458+
end
459+
if key_len > 65535 then
460+
return nil, "key too long"
461+
end
462+
463+
local old_str_val_buf
464+
local old_str_val_len = 0
465+
local old_num_val = 0
466+
local old_valtyp = type(old_value)
467+
468+
if old_valtyp == "string" then
469+
old_valtyp = 4 -- LUA_TSTRING
470+
old_str_val_buf = old_value
471+
old_str_val_len = #old_value
472+
473+
elseif old_valtyp == "number" then
474+
old_valtyp = 3 -- LUA_TNUMBER
475+
old_num_val = old_value
476+
477+
elseif old_value == nil then
478+
old_valtyp = 0 -- LUA_TNIL
479+
480+
elseif old_valtyp == "boolean" then
481+
old_valtyp = 1 -- LUA_TBOOLEAN
482+
old_num_val = old_value and 1 or 0
483+
484+
else
485+
return nil, "bad old_value type"
486+
end
487+
488+
local size = get_string_buf_size()
489+
local buf = get_string_buf(size)
490+
str_value_buf[0] = buf
491+
local value_len = get_size_ptr()
492+
value_len[0] = size
493+
494+
local rc = ngx_lua_ffi_shdict_get_if_not_eq(zone, key, key_len,
495+
old_valtyp, old_str_val_buf,
496+
old_str_val_len,
497+
old_num_val, old_flags,
498+
value_type,
499+
str_value_buf, value_len,
500+
num_value, user_flags,
501+
match_flags, match, errmsg)
502+
if rc ~= 0 then
503+
if match[0] == 1 then
504+
return nil, false
505+
elseif errmsg[0] ~= nil then
506+
return nil, ffi_str(errmsg[0])
507+
end
508+
509+
error("failed to get the key")
510+
end
511+
512+
local typ = value_type[0]
513+
514+
if typ == 0 then -- LUA_TNIL
515+
return nil
516+
end
517+
518+
local flags = tonumber(user_flags[0])
519+
520+
local val
521+
522+
if typ == 4 then -- LUA_TSTRING
523+
if str_value_buf[0] ~= buf then
524+
-- ngx.say("len: ", tonumber(value_len[0]))
525+
buf = str_value_buf[0]
526+
val = ffi_str(buf, value_len[0])
527+
C.free(buf)
528+
else
529+
val = ffi_str(buf, value_len[0])
530+
end
531+
532+
elseif typ == 3 then -- LUA_TNUMBER
533+
val = tonumber(num_value[0])
534+
535+
elseif typ == 1 then -- LUA_TBOOLEAN
536+
val = (tonumber(buf[0]) ~= 0)
537+
538+
else
539+
error("unknown value type: " .. typ)
540+
end
541+
542+
if flags ~= 0 then
543+
return val, flags
544+
end
545+
546+
return val
547+
end
548+
294549

295550
local function shdict_get(zone, key)
296551
zone = check_zone(zone)
@@ -630,6 +885,8 @@ if dict then
630885
mt.expire = shdict_expire
631886
mt.capacity = shdict_capacity
632887
mt.free_space = shdict_free_space
888+
mt.cas = shdict_cas
889+
mt.get_if_not_eq = shdict_get_if_not_eq
633890
end
634891
end
635892
end

0 commit comments

Comments
 (0)