Merge branch 'mongors' into dev

This commit is contained in:
Cloud Wu
2014-07-21 14:28:09 +08:00
2 changed files with 171 additions and 94 deletions

View File

@@ -75,22 +75,51 @@ local function dispatch_reply(so)
return reply_id, succ, result return reply_id, succ, result
end end
local function __parse_addr(addr)
local host, port = string.match(addr, "([^:]+):(.+)")
return host, tonumber(port)
end
local function mongo_auth(mongoc) local function mongo_auth(mongoc)
local user = rawget(mongoc, "username") local user = rawget(mongoc, "username")
local pass = rawget(mongoc, "password") local pass = rawget(mongoc, "password")
if user == nil or pass == nil then
return
end
return function() return function()
if user ~= nil and pass ~= nil then
assert(mongoc:auth(user, pass)) assert(mongoc:auth(user, pass))
end end
local rs_data = mongoc:runCommand("ismaster")
if rs_data.ok == 1 then
if rs_data.hosts then
local backup = {}
for _, v in ipairs(rs_data.hosts) do
local host, port = __parse_addr(v)
table.insert(backup, {host = host, port = port})
end
mongoc.__sock:changebackup(backup)
end
if rs_data.ismaster then
return
else
local host, port = __parse_addr(rs_data.primary)
mongoc.host = host
mongoc.port = port
mongoc.__sock:changehost(host, port)
end
end
end
end end
function mongo.client( conf ) function mongo.client( conf )
local first = conf
local backup = nil
if conf.rs then
first = conf.rs[1]
backup = conf.rs
end
local obj = { local obj = {
host = conf.host, host = first.host,
port = conf.port or 27017, port = first.port or 27017,
} }
obj.__id = 0 obj.__id = 0
@@ -99,6 +128,7 @@ function mongo.client( conf )
port = obj.port, port = obj.port,
response = dispatch_reply, response = dispatch_reply,
auth = mongo_auth(obj), auth = mongo_auth(obj),
backup = backup,
} }
setmetatable(obj, client_meta) setmetatable(obj, client_meta)
obj.__sock:connect(true) -- try connect only once obj.__sock:connect(true) -- try connect only once

View File

@@ -26,6 +26,7 @@ function socket_channel.channel(desc)
local c = { local c = {
__host = assert(desc.host), __host = assert(desc.host),
__port = assert(desc.port), __port = assert(desc.port),
__backup = desc.backup,
__auth = desc.auth, __auth = desc.auth,
__response = desc.response, -- It's for session mode __response = desc.response, -- It's for session mode
__request = {}, -- request seq { response func or session } -- It's for order mode __request = {}, -- request seq { response func or session } -- It's for order mode
@@ -152,34 +153,66 @@ local function dispatch_function(self)
end end
end end
local function connect_backup(self)
if self.__backup then
for _, addr in ipairs(self.__backup) do
local host, port
if type(addr) == "table" then
host, port = addr.host, addr.port
else
host = addr
port = self.__port
end
skynet.error("socket: connect to backup host", host, port)
local fd = socket.open(host, port)
if fd then
self.__host = host
self.__port = port
return fd
end
end
end
end
local function connect_once(self) local function connect_once(self)
if self.__closed then
return false
end
assert(not self.__sock and not self.__authcoroutine) assert(not self.__sock and not self.__authcoroutine)
local fd = socket.open(self.__host, self.__port) local fd = socket.open(self.__host, self.__port)
if not fd then
fd = connect_backup(self)
if not fd then if not fd then
return false return false
end end
self.__authcoroutine = coroutine.running() end
self.__sock = setmetatable( {fd} , channel_socket_meta ) self.__sock = setmetatable( {fd} , channel_socket_meta )
skynet.fork(dispatch_function(self), self) skynet.fork(dispatch_function(self), self)
if self.__auth then if self.__auth then
self.__authcoroutine = coroutine.running()
local ok , message = pcall(self.__auth, self) local ok , message = pcall(self.__auth, self)
if not ok then if not ok then
close_channel_socket(self) close_channel_socket(self)
if message ~= socket_error then if message ~= socket_error then
self.__authcoroutine = false
skynet.error("socket: auth failed", message) skynet.error("socket: auth failed", message)
end end
end end
self.__authcoroutine = false self.__authcoroutine = false
if ok and not self.__sock then
-- auth may change host, so connect again
return connect_once(self)
end
return ok return ok
end end
self.__authcoroutine = false
return true return true
end end
local function try_connect(self , once) local function try_connect(self , once)
local t = 100 local t = 0
while not self.__closed do while not self.__closed do
if connect_once(self) then if connect_once(self) then
if not once then if not once then
@@ -292,6 +325,20 @@ function channel:close()
end end
end end
function channel:changehost(host, port)
self.__host = host
if port then
self.__port = port
end
if not self.__closed then
close_channel_socket(self)
end
end
function channel:changebackup(backup)
self.__backup = backup
end
channel_meta.__gc = channel.close channel_meta.__gc = channel.close
local function wrapper_socket_function(f) local function wrapper_socket_function(f)