lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


2011/3/24 Alexander Gladysh <agladysh@gmail.com>:
> On Thu, Mar 24, 2011 at 19:57, Jerome Vuarand <jerome.vuarand@gmail.com> wrote:
>> 2011/3/24 Alexander Gladysh <agladysh@gmail.com>:
>>>>> I would wrap status/error replies in a status userdata object with a is_error
>>>>> field/method.  For string/number reply values convert them to basic lua
>>>>> string/numbers.
>
>>>> Interesting idea. I'm trying to imagine how the user's code would look
>>>> like. Wouldn't it be too cumbersome to work with?
>
>>> Also, I'm concerned by the overhead — status replies are common in the
>>> protocol, and creating an userdata per each can be too much (strings
>>> should be cheaper, and, besides, users do not need to look into status
>>> codes that often, I think).
>
>> To avoid clash with strings, you can have your status codes be
>> userdata without allocating one at each request. Just keep a redis.ok
>> value that you return, and client code can write "if status==redis.ok
>> then end".
>
> Have to do strcmpi() or something for this in C code first. (Not a big problem.)

You can use Lua to avoid the strcmpi. Just push the string, and index
the table where you put the userdata (see below).

>> That being said, I think (please correct me if I'm wrong) that string
>> allocation is not cheaper in terms of execution speed than userdata
>> allocation, unless most of the strings are expected to be already
>> interned (which completely depends on the data your client will put in
>> your redis db).
>
> Well, as I understand, in this case, it does not depend on data in db
> — we're discussing status codes.
>
> There are (I think, please correct me) two common status replies
> (REDIS_REPLY_STATUS) in Redis: OK and QUEUED (for multi/exec).
>
> I could cache these two, and if I encounter anything else, I'll just
> allocate a new one. (Actually, I'll cache a Redis NIL as well — looks
> like it needs to be separate from Lua nil — not so sure about this
> though.)
>
> But the question is how to actually write the thing then:
>
> 1. Where is the best place to store actual hiredis.OK and
> hiredis.QUEUED values, so they are easily accessible by the C code?

One common way to share such constants between the C implementation
and the Lua client code, is to put them in the module table. To get
easy access to the module table, a common practice is to have the
module be the function environment of your lua_CFunction-s. To do
that, in the luaopen_<modname> function, first create the module table
(1), then duplicate the reference (2), make the table the current
environment (3), and register your functions (4):

static luaL_Reg empty[] = {{0, 0}};
static luaL_Reg functions[] = {
  /* put your binding there */
  {0, 0}
};

int luaopen_mymodule(lua_State* L)
{
  /* init the module */
  luaL_register(L, lua_tostring(L, 1), empty); /* (1) */
  /* set as fenv */
  lua_pushvalue(L, -1); /* (2) */
  lua_replace(L, LUA_ENVIRONINDEX); /* (3) */
  /* register the functions */
  luaL_register(L, 0, functions); /* (4) */
  /* create ok and queued (zero-sized) udata */
  lua_newuserdata(L, 0);
  lua_setfield(L, -2, "ok");
  lua_newuserdata(L, 0);
  lua_setfield(L, -2, "queued");
  return 0;
}

> 2. What is the best way to handle REDIS_REPLY_STATUS case? Just bite
> the bullet and do two string comparisons? Or does anyone see something
> more clever?

So redis gives you a C string ? Just use it as a key in the module
table, which you previously set as all your lua_CFunction-s
environment:

{
  const char* redis_result;
  ... /* get a value for redis_result */
  lua_getfield(L, LUA_ENVIRONINDEX, redis_result);
  return 1;
}