aboutsummaryrefslogtreecommitdiffstats
path: root/openresty-ext/src/assembly/resources/openresty/nginx/luaext/dao/redis_db.lua
blob: d35cb8e0c8cdf95ac3ef9ffb265f1eea00c8ac3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
--[[

    Copyright (C) 2016 ZTE, Inc. and others. All rights reserved. (ZTE)

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

            http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

--]]

-- the client for redis, include the connection pool management and api implements
local redis = require('resty.redis')
local tbl_util  = require('lib.utils.table_util')

local _M = {
}
_M._VERSION = '0.0.1'
_M._DESCRIPTION = 'msb_redis_module'

local mt = { __index = _M }

local tbl_insert = table.insert
local tbl_sort = table.sort
local tbl_isempty = tbl_util.isempty

function _M.new(self, conf)
	self.host        = conf.host
	self.port        = conf.port
	self.timeout     = conf.timeout
	self.dbid        = conf.dbid
	self.poolsize    = conf.poolsize
	self.idletimeout = conf.idletimeout

	local red = redis:new()
	return setmetatable({redis = red}, mt)
end

function _M.connectdb(self)
	local host  = self.host
	local port  = self.port
	local dbid  = self.dbid
	local red   = self.redis

	if not (host and port) then
		return nil, 'no host:port avaliable provided'
	end

	--set default value
	if not dbid then dbid = 0 end
	local timeout   = self.timeout 
	if not timeout then 
		timeout = 1000   -- 1s
	end

	red:set_timeout(timeout)

	local ok, err 
	if host and port then
		ok, err = red:connect(host, port)
		if ok then return red:select(dbid) end
	end

	return ok, err
end

function _M.keepalivedb(self)
	local   max_idle_timeout  = self.idletimeout --ms
	local   pool_size         = self.poolsize

	if not pool_size then pool_size = 100 end
	if not max_idle_timeout then max_idle_timeout = 90000 end --90s

	local ok, err = self.redis:set_keepalive(max_idle_timeout, pool_size)
	if not ok then
		ngx.log(ngx.ERR, "redis pool keepalive error",err)
		return
	end
	return
end

--inner function,only used in this module
local function _hgetall(red,key)
	local resp,err = red:hgetall(key)
	--if not resp or next(resp) == nil then
	if tbl_isempty(resp) then
		return nil, "key "..key.." not found"
	end
	local hashinfo = red:array_to_hash(resp)
	return hashinfo,nil
end

function _M.getserviceinfo(self,key)
	if not key then
		return nil,'no key is provided'
	end
	local c, err = self:connectdb()
	if not c then
		return nil, err
	end

	local red   = self.redis
	local resp,err = red:get(key) --the key will create dynamically
	self:keepalivedb()
	if not resp or resp == ngx.null then
		return nil, "key "..key.." not found"
	else
		return resp,nil
	end
end

function _M.getbackservers(self,keypattern)
	if not keypattern then
		return nil,'no keypattern is provided'
	end
	local c, err = self:connectdb()
	if not c then
		return nil, err
	end

	local red = self.redis

	local resp, err = red:keys(keypattern)
	if tbl_isempty(resp) then
		self:keepalivedb()
		return nil, "no server matched"
	end

	local servers = {}
	for i, v in ipairs(resp) do
		local serverinfo,err = _hgetall(red,v)
		if serverinfo then
			tbl_insert(servers,serverinfo)
		end
	end
	self:keepalivedb()
	return servers,nil
end

function _M.getcustomsvcnames(self,keypattern)
	if not keypattern then
		return nil,'no keypattern is provided'
	end
	local c, err = self:connectdb()
	if not c then
		return nil, err
	end

	local red = self.redis
	--store svc names into the Set
	local svcname_set={}

	local res, err = red:scan("0","count",50,"match",keypattern)
	if not res then
		self:keepalivedb()
		return {}, "failed to scan in getcustomsvcnames()"
	end

	local cursor, keys, err = unpack(res)
	for _, svckey in ipairs(keys) do
		local m, err = ngx.re.match(svckey, "^.+:custom:([^:]+)", "o")
		if m then
			svcname_set[m[1]]=true
		end
	end

	while( cursor ~= "0" )
	do
		res = red:scan(cursor,"count",50,"match",keypattern)
		if not res then
			break
		end
		cursor, keys, err = unpack(res)
		for _, svckey in ipairs(keys) do
			local m, err = ngx.re.match(svckey, "^.+:custom:([^:]+)", "o")
			if m then
				svcname_set[m[1]]=true
			end
		end
	end
	self:keepalivedb()
	local svcnames = {}
	for svcname,_ in pairs(svcname_set) do
		tbl_insert(svcnames,svcname)
	end
	--sort the key_table in reverse order
	tbl_sort(svcnames, function (a, b)
			return a > b
		end)
	return svcnames,nil
end
return _M