daurnimator / lredis

A redis client for lua
MIT License
42 stars 7 forks source link

Reuse protocol implementation from lluv-redis. #1

Closed moteus closed 9 years ago

moteus commented 9 years ago

This is just suggestion. lluv-redis implement protocol in independent from libuv and in fact it pure lua. Basic usage

--- Stream class do protocol decode/encode

-- all handlers gets SELF as first argument
stream = RedisStream.new(SELF)
-- do write here
:on_command(function(self, data)
  -- write `data` to output stream
  -- call 
end)
-- handle async messages here
:on_message(function(self, channel, data)
end)
-- internal or protocol error
:on_halt(function(self, err)
end)

-- read data from input stream
chunk = io.read

-- append data to stream and execute 
stream:append(chunk):execute()

-- any command 
stream:command(<COMMAND HERE>, function(self, err, result)
...
end)

--- Commander class encode/decode arguments/reuslts of command

command = RedisCommander.new(stream)
command:ping(function(self, err, ok) end)

This is basic example of implement sync client based on LuaSocket

daurnimator commented 9 years ago

lluv-redis implement protocol in independent from libuv and in fact it pure lua.

hrm. I didn't realise that. I actually didn't find lluv-redis until after I wrote lredis.

I actually wrote lredis with library neutrality in mind. All the protocol level stuff is in https://github.com/daurnimator/lredis/blob/master/lredis/protocol.lua and can be reused. While I put the cqueues specific stuff (i.e. network opertations and scheduling) in https://github.com/daurnimator/lredis/blob/master/lredis/cqueues.lua

It's all quite small.... I'm not sure what the value of code reuse here will be...

moteus commented 9 years ago

My implementation in callback based and allows queued commands. But you do not use callback and you do not need queue. As I can see my sync.lua should work with cqueus just need replace socket:recv to file:read. But It require one more level or coroutine and pack and unpack arguments So may be it not worth it.

daurnimator commented 9 years ago

you do not need queue.

I do have a queue (fifo); it's in the cqueues specific bit.

moteus commented 9 years ago

I mean command queue

-- here we enqueue 2 command with their callback.
cli:ping(cb)
cli:ping(cb)

I think you need just queue data recived from Server because each call is sync so command executed one by one.

daurnimator commented 9 years ago

For lredis you just use the coroutine scheduler for that (make two coroutines and use the same redis object from each)

local r = require "lredis.cqueues".new(...)
local cq = require "cqueues".new()
cq:wrap(function()
    print("PING1", r:ping())
end)
cq:wrap(function()
    print("PING2", r:ping())
end)
assert(cq:loop())

The two above ping commands will be pipelined :)

moteus commented 9 years ago

But if you need make 2 io operation e.g. write to memcache and redis then one operation shold wait anothe or you need provide something like select for coroutine or use one more coroutine. But I agree that in some cases it very convinient. And there no problem convert callback based calls to coroutine based (and vice versa). As I said if you have interest you can try sync.lua but you can not use same socket from several coroutines :)

daurnimator commented 9 years ago

But if you need make 2 io operation e.g. write to memcache and redis then one operation shold wait anothe or you need provide something like select for coroutine or use one more coroutine.

cqueues provides all sorts of primitives to do those sorts of things; you should check it out :)

moteus commented 9 years ago

you should check it out

Only after you port it on Windows. :) And use async io and then emulate sync on top of that and then use async calls using this ... It's kind of not straight way.

And after that you also may need sinchronization with mutexes to execute several commands. :)

daurnimator commented 9 years ago

Only after you port it on Windows. :) And use async io and then emulate sync on top of that and then use async calls using this ... It's kind of not straight way.

Working on it :) via http://midipix.org very cool project (but getting off topic for here)

And after that you also may need sinchronization with mutexes to execute several commands. :)

Not mutexes, but lightweight condition variables: they're provided by the cqueues.condition module.

daurnimator commented 9 years ago

btw, I just added a pipelining example: https://github.com/daurnimator/lredis/blob/master/examples/pipelining.lua

Let me know if you'd like me to expand on the lredis vs lluv-redis comparison; or have points to add yourself :)