batch mode in redis

This commit is contained in:
云风
2013-01-06 12:15:59 +08:00
parent 1cf9e9d1ee
commit ac7f67f982
3 changed files with 108 additions and 6 deletions

View File

@@ -2,8 +2,10 @@ local skynet = require "skynet"
local string = string
local table = table
local unpack = unpack
local assert = assert
local redis_manager
local batch = false
local redis = {}
@@ -12,21 +14,40 @@ local command = {}
setmetatable(command, { __index = function(t,k)
local cmd = string.upper(k)
local f = function(self, ...)
local err, result = skynet.call( self.__handle, "lua", cmd, ...)
assert(err, result)
return result
if batch then
skynet.send( self.__handle, "lua", cmd , ...)
else
local err, result = skynet.call( self.__handle, "lua", cmd, ...)
assert(err, result)
return result
end
end
t[k] = f
return f
end})
function command:exists(key)
assert(not batch, "exists can't used in batch mode")
local result , exists = skynet.call( self.__handle, "lua" , "EXISTS", key)
assert(result, exists)
exists = exists ~= 0
return exists
end
function command:batch(mode)
if mode == "end" then
assert(batch, "Open batch mode first")
batch = false
local err, result = skynet.unpack(skynet.rawcall( self.__handle, "text", mode))
assert(err, result)
return result
else
assert(mode == "read" or mode == "write")
batch = mode
skynet.send( self.__handle, "text", mode)
end
end
local meta = {
__index = command
}

View File

@@ -6,6 +6,9 @@ local table = table
local tonumber = tonumber
local ipairs = ipairs
local unpack = unpack
local batch_mode = {}
local batch_count = {}
local batch_reply = {}
local redis_server, redis_db = ...
local function compose_message(msg)
@@ -46,9 +49,48 @@ local function pop_request_queue()
return reply
end
local function response(...)
local function batch_close(address,session)
local reply = batch_reply[address]
skynet.redirect(address,0, "response", session, skynet.pack(not (type(reply) == "string"), reply))
batch_mode[address] = nil
batch_count[address] = nil
batch_reply[address] = nil
end
local function batch_dec(address)
local bc = batch_count[address]
batch_count[address] = bc - 1
if bc == 1 then
local session = batch_mode[address]
if type(session) == "number" then
batch_close(address, session)
end
end
end
local function response(suc, value)
local reply = pop_request_queue()
skynet.redirect(reply.address,0, "response", reply.session, skynet.pack(...))
local mode = reply.batch
local address = reply.address
if mode == "read" then
if suc then
local br = batch_reply[address]
if type(br) == "table" then
br.n = br.n + 1
br[br.n] = value
end
else
batch_reply[address] = value
end
batch_dec(address)
elseif mode == "write" then
if not suc then
batch_reply[address] = value
end
batch_dec(address)
else
skynet.redirect(address,0, "response", reply.session, skynet.pack(suc, value))
end
end
local function readline(sep)
@@ -159,11 +201,37 @@ skynet.register_protocol {
}
skynet.start(function()
skynet.dispatch("text", function(session, address, mode)
local last = batch_mode[address]
if mode == "end" then
assert(last == "read" or last == "write" , "Invalid end")
if batch_count[address] == 0 then
batch_close(address, session)
else
batch_mode[address] = session
end
else
assert(last == nil, "Already in batch mode")
if mode == "read" then
batch_reply[address] = { n = 0 }
batch_count[address] = 0
elseif mode == "write" then
batch_count[address] = 0
else
error ("Invalid last batch operation : " .. last)
end
batch_mode[address] = mode
end
end)
skynet.dispatch("lua", function(session, address, ...)
local message = { ... }
local cmd = compose_message(message)
socket.write(cmd)
push_request_queue { session = session , address = address, cmd = cmd }
local mode = batch_mode[address]
if mode == "read" or mode == "write" then
batch_count[address] = batch_count[address] + 1
end
push_request_queue { session = session , address = address, cmd = cmd , batch = mode }
end)
init()
end)

View File

@@ -3,9 +3,22 @@ local redis = require "redis"
skynet.start(function()
local db = redis.connect "main"
db:batch "write" -- ignore results
db:set("A", "hello")
db:set("B", "world")
db:batch "end"
db:batch "read"
db:get("A")
db:get("B")
local r = db:batch "end" -- return all results in a table
for k,v in pairs(r) do
print(k,v)
end
print(db:exists "A")
print(db:get "A")
print(db:set("A","hello world"))
print(db:get("A"))
skynet.exit()
end)