new socket service and socket lib instead of old connection, and rewrite redis lib

This commit is contained in:
云风
2013-06-21 13:02:51 +08:00
parent 0ffd9b8b8e
commit 277b6957cb
16 changed files with 1182 additions and 1248 deletions

View File

@@ -1,65 +1,168 @@
local skynet = require "skynet"
local string = string
local table = table
local unpack = unpack
local assert = assert
local socket = require "socket"
local config = require "config"
local redis_conf = skynet.getenv "redis"
local name = config (redis_conf)
local redis_manager
local batch = false
local readline = socket.readline
local readbytes = socket.read
local table = table
local string = string
local redis = {}
local command = {}
local meta = {
__index = command,
__gc = function(self)
socket.close(self.__handle)
end,
}
function redis.connect(dbname)
local fd = socket.open(name[dbname])
return setmetatable( { __handle = fd, __mode = false }, meta )
end
function command:disconnect()
socket.close(self.__handle)
setmetatable(self, nil)
end
local function compose_message(msg)
local lines = { "*" .. #msg }
for _,v in ipairs(msg) do
local t = type(v)
if t == "number" then
v = tostring(v)
elseif t == "userdata" then
v = int64.tostring(int64.new(v),10)
end
table.insert(lines,"$"..#v)
table.insert(lines,v)
end
table.insert(lines,"")
local cmd = table.concat(lines,"\r\n")
return cmd
end
local redcmd = {}
redcmd[42] = function(fd, data) -- '*'
local n = tonumber(data)
if n < 0 then
return true, nil
end
local bulk = {}
for i = 1,n do
local line = readline(fd,"\r\n")
local bytes = tonumber(string.sub(line,2))
if bytes < 0 then
table.insert(bulk, nil)
else
local data = readbytes(fd, bytes + 2)
table.insert(bulk, string.sub(data,1,-3))
end
end
return true, bulk
end
redcmd[36] = function(fd, data) -- '$'
local bytes = tonumber(data)
if bytes < 0 then
return true,nil
end
local firstline = readbytes(fd, bytes+2)
return true,string.sub(firstline,1,-3)
end
redcmd[43] = function(fd, data) -- '+'
return true,data
end
redcmd[45] = function(fd, data) -- '-'
return false,data
end
redcmd[58] = function(fd, data) -- ':'
-- todo: return string later
return true, tonumber(data)
end
local function read_response(fd)
local result = readline(fd, "\r\n")
local firstchar = string.byte(result)
local data = string.sub(result,2)
return redcmd[firstchar](fd,data)
end
setmetatable(command, { __index = function(t,k)
local cmd = string.upper(k)
local f = function(self, ...)
if batch then
skynet.send( self.__handle, "lua", cmd , ...)
local f = function (self, ...)
local fd = self.__handle
if self.__mode then
socket.write(fd, compose_message { cmd, ... })
self.__batch = self.__batch + 1
else
local err, result = skynet.call( self.__handle, "lua", cmd, ...)
assert(err, result)
return result
socket.lock(fd)
socket.write(fd, compose_message { cmd, ... })
local ok, ret = read_response(fd)
socket.unlock(fd)
return ok, ret
end
end
t[k] = f
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)
assert(not self.__mode, "exists can't used in batch mode")
local fd = self.__handle
socket.lock(fd)
socket.write(fd, compose_message { "EXISTS", key })
local ok, exists = read_response(fd)
socket.unlock(fd)
assert(ok, 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
local fd = self.__handle
if self.__mode == "read" then
local allok = true
local allret = {}
for i = 1, self.__batch do
local ok, ret = read_response(fd)
allok = allok and ok
allret[i] = ret
end
assert(allok, "batch read failed")
socket.unlock(self.__handle)
self.__mode = false
return allret
else
local allok = true
local allret = true
for i = 1, self.__batch do
local ok, ret = read_response(fd)
allok = allok and ok
if ret~="OK" then
allret = false
end
end
socket.unlock(self.__handle)
self.__mode = false
assert(allret, "reading in batch write")
return allok
end
else
assert(mode == "read" or mode == "write")
batch = mode
skynet.send( self.__handle, "text", mode)
self.__mode = mode
self.__batch = 0
socket.lock(self.__handle)
end
end
local meta = {
__index = command
}
function redis.connect(dbname)
local handle = skynet.call(redis_manager, "lua", dbname)
assert(handle ~= nil)
return setmetatable({ __handle = handle } , meta)
end
skynet.init(function()
redis_manager = skynet.uniqueservice("redis-mgr")
end, "redis")
return redis