mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 08:08:53 -05:00
Scripting: objects caching for Lua c->argv creation.
Reusing small objects when possible is a major speedup under certain conditions, since it is able to avoid the malloc/free pattern that otherwise is performed for every argument in the client command vector.
This commit is contained in:
parent
1e4ba6e7e6
commit
4f686555ce
@ -200,6 +200,8 @@ void luaSortArray(lua_State *lua) {
|
||||
lua_pop(lua,1); /* Stack: array (sorted) */
|
||||
}
|
||||
|
||||
#define LUA_CMD_OBJCACHE_SIZE 32
|
||||
#define LUA_CMD_OBJCACHE_MAX_LEN 64
|
||||
int luaRedisGenericCommand(lua_State *lua, int raise_error) {
|
||||
int j, argc = lua_gettop(lua);
|
||||
struct redisCommand *cmd;
|
||||
@ -209,6 +211,8 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
|
||||
/* Cached across calls. */
|
||||
static robj **argv = NULL;
|
||||
static int argv_size = 0;
|
||||
static robj *cached_objects[LUA_CMD_OBJCACHE_SIZE];
|
||||
static int cached_objects_len[LUA_CMD_OBJCACHE_SIZE];
|
||||
|
||||
/* Require at least one argument */
|
||||
if (argc == 0) {
|
||||
@ -231,7 +235,20 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
|
||||
|
||||
obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
|
||||
if (obj_s == NULL) break; /* Not a string. */
|
||||
argv[j] = createStringObject(obj_s, obj_len);
|
||||
|
||||
/* Try to use a cached object. */
|
||||
if (cached_objects[j] && cached_objects_len[j] >= obj_len) {
|
||||
char *s = cached_objects[j]->ptr;
|
||||
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
|
||||
|
||||
argv[j] = cached_objects[j];
|
||||
cached_objects[j] = NULL;
|
||||
memcpy(s,obj_s,obj_len+1);
|
||||
sh->free += sh->len - obj_len;
|
||||
sh->len = obj_len;
|
||||
} else {
|
||||
argv[j] = createStringObject(obj_s, obj_len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if one of the arguments passed by the Lua script
|
||||
@ -348,8 +365,28 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
|
||||
cleanup:
|
||||
/* Clean up. Command code may have changed argv/argc so we use the
|
||||
* argv/argc of the client instead of the local variables. */
|
||||
for (j = 0; j < c->argc; j++)
|
||||
decrRefCount(c->argv[j]);
|
||||
for (j = 0; j < c->argc; j++) {
|
||||
robj *o = c->argv[j];
|
||||
|
||||
/* Try to cache the object in the cached_objects array.
|
||||
* The object must be small, SDS-encoded, and with refcount = 1
|
||||
* (we must be the only owner) for us to cache it. */
|
||||
if (j < LUA_CMD_OBJCACHE_SIZE &&
|
||||
o->refcount == 1 &&
|
||||
(o->encoding == REDIS_ENCODING_RAW ||
|
||||
o->encoding == REDIS_ENCODING_EMBSTR) &&
|
||||
sdslen(o->ptr) <= LUA_CMD_OBJCACHE_MAX_LEN)
|
||||
{
|
||||
struct sdshdr *sh = (void*)(((char*)(o->ptr))-(sizeof(struct sdshdr)));
|
||||
|
||||
if (cached_objects[j]) decrRefCount(cached_objects[j]);
|
||||
cached_objects[j] = o;
|
||||
cached_objects_len[j] = sh->free + sh->len;
|
||||
} else {
|
||||
decrRefCount(o);
|
||||
}
|
||||
}
|
||||
|
||||
if (c->argv != argv) {
|
||||
zfree(c->argv);
|
||||
argv = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user