├── README.md
├── lib
└── resty
│ └── bloomd.lua
└── t
└── test.lua
/README.md:
--------------------------------------------------------------------------------
1 | Name
2 | ====
3 |
4 | lua-resty-bloomd - Is a client library based on ngx_lua to interface with bloomd servers(https://github.com/armon/bloomd)
5 |
6 | Bloomd is a high-performance C server which is used to expose bloom filters and operations over them to networked clients.
7 |
8 | Table of Contents
9 | =================
10 |
11 | * [Name](#name)
12 | * [Status](#status)
13 | * [Synopsis](#synopsis)
14 | * [Methods](#methods)
15 | * [new](#new)
16 | * [create](#create)
17 | * [list](#list)
18 | * [drop](#drop)
19 | * [close](#close)
20 | * [clear](#clear)
21 | * [check](#check)
22 | * [checks](#checks)
23 | * [set](#set)
24 | * [sets](#sets)
25 | * [info](#info)
26 | * [flush](#flush)
27 | * [Installation](#installation)
28 | * [Authors](#authors)
29 | * [Copyright and License](#copyright-and-license)
30 |
31 | Status
32 | ======
33 |
34 | This library is production ready.
35 |
36 | Synopsis
37 | ========
38 | ```lua
39 | lua_package_path "/path/to/lua-resty-bloomd/lib/?.lua;;";
40 |
41 | server {
42 | location /test {
43 | content_by_lua '
44 | local bloomd = require("resty.bloomd")
45 |
46 | local function debug(name, ok, err)
47 | if type(err) == 'table' then
48 | local t = {}
49 | for k, v in pairs(err) do
50 | table.insert(t, k .. ":" .. tostring(v))
51 | end
52 | err = table.concat(t, ",")
53 | end
54 | ngx.say(string.format("%15s -- ok: %5s, err: %s", name, tostring(ok), tostring(err)))
55 | end
56 | -- create a new instance and connect to the bloomd(127.0.0.1:8673)
57 | local filter_obj = bloomd:new("127.0.0.1", 8673, 2000)
58 | local function test_main()
59 | local filter_name = "my_filter"
60 | local capacity = 100001
61 | local probability = 0.001
62 | -- create a filter named filter_name
63 | local ok, err = filter_obj:create(filter_name, capacity, probability)
64 | debug("create-new", ok, err)
65 | assert(ok == true)
66 | -- assert(err == "Done", "err ~= 'Done'")
67 |
68 | -- create a filter, the name is exist
69 | local ok, err = filter_obj:create(filter_name, capacity, probability)
70 | debug("create-exist", ok, err)
71 | assert(ok == true)
72 | assert(err == "Exists")
73 |
74 | -- set a key, New
75 | local ok, err = filter_obj:set(filter_name, 'my_key')
76 | debug("set-new", ok, err)
77 | assert(ok==true)
78 | assert(err == "Yes")
79 |
80 | -- set a key, Exist
81 | local ok, err = filter_obj:set(filter_name, 'my_key')
82 | debug("set-exist", ok, err)
83 | assert(ok==true)
84 | assert(err == "No")
85 |
86 | -- check a key, Exist
87 | local ok, err = filter_obj:check(filter_name, 'my_key')
88 | debug("check-exist", ok, err)
89 | assert(ok==true)
90 | assert(err == "Yes")
91 |
92 | -- check a key, Not Exist
93 | local ok, err = filter_obj:check(filter_name, 'this_key_not_exist')
94 | debug("check-not-exist", ok, err)
95 | assert(ok==true)
96 | assert(err == "No")
97 |
98 | -- flush a filter
99 | local ok, err = filter_obj:flush(filter_name)
100 | debug("flush", ok, err)
101 | assert(ok==true)
102 | assert(err == "Done")
103 |
104 | -- close a bloom filter
105 | local ok, err = filter_obj:close(filter_name)
106 | debug("close", ok, err)
107 | assert(ok==true)
108 | assert(err == "Done")
109 |
110 | -- check a key, Exist
111 | local ok, err = filter_obj:check(filter_name, 'my_key')
112 | debug("check-exist", ok, err)
113 | assert(ok==true)
114 | assert(err == "Yes")
115 |
116 |
117 | filter_obj:create("my_filter3", capacity, 0.001)
118 | -- list all filter
119 | local ok, filters = filter_obj:list(filter_name)
120 | debug("list", ok, filters)
121 | assert(ok==true)
122 | assert(type(filters)=='table' and #filters==2)
123 | for _,filter in ipairs(filters) do
124 | if filter.name == filter_name then
125 | assert(filter.size == 1)
126 | end
127 | end
128 | filter_obj:drop('my_filter3')
129 |
130 | -- Set many items in a filter at once(bulk command)
131 | local ok, status = filter_obj:sets(filter_name, {"a", "b", "c"})
132 | assert(ok)
133 | assert(type(status)=='table')
134 | err = table.concat(status, ' ')
135 | debug("sets", ok, err)
136 | assert(err == "Yes Yes Yes")
137 |
138 | local ok, status = filter_obj:sets(filter_name, {"a", "b", "d"})
139 | assert(ok)
140 | assert(type(status)=='table')
141 | err = table.concat(status, ' ')
142 | debug("sets", ok, err)
143 | assert(err == "No No Yes")
144 |
145 | -- Checks if a list of keys are in a filter
146 | local ok, status = filter_obj:checks(filter_name, {"a", "x", "c", "d", "e"})
147 | assert(ok)
148 | assert(type(status)=='table')
149 | err = table.concat(status, ' ')
150 | debug("checks", ok, err)
151 | assert(err == "Yes No Yes Yes No")
152 |
153 |
154 | -- Gets info about a filter
155 | local ok, info = filter_obj:info(filter_name)
156 | debug("info", ok, info)
157 | assert(ok)
158 | assert(type(info)=='table')
159 | assert(info.capacity == capacity)
160 | assert(info.probability == probability)
161 | assert(info.size == 5)
162 |
163 | -- drop a filter
164 | local ok, err = filter_obj:drop(filter_name)
165 | debug("drop", ok, err)
166 | assert(ok==true)
167 | assert(err == "Done")
168 |
169 |
170 | -- Test filter not exist
171 | local ok, err = filter_obj:drop(filter_name)
172 | debug("drop-not-exist", ok, err)
173 | assert(ok==false)
174 | assert(err == "Filter does not exist")
175 |
176 |
177 | -- create, close and clear a bloom filter, my_filter2 is still in disk.
178 | local ok, err = filter_obj:create("my_filter2", 10000*20, 0.001)
179 | debug("create-new", ok, err)
180 | assert(ok == true)
181 | assert(err == "Done", "err ~= 'Done'")
182 | local ok, err = filter_obj:close("my_filter2")
183 | debug("close", ok, err)
184 | assert(ok==true)
185 | assert(err == "Done")
186 | local ok, err = filter_obj:clear("my_filter2")
187 | debug("clear", ok, err)
188 | assert(ok==true)
189 | assert(err == "Done")
190 |
191 | ngx.say("--------- all test ok --------------")
192 | end
193 | local ok, err = pcall(test_main)
194 | if not ok then
195 | filter_obj:close("my_filter")
196 | filter_obj:close("my_filter2")
197 | filter_obj:close("my_filter3")
198 | assert(ok, err)
199 | end
200 | ';
201 | }
202 | }
203 | ```
204 |
205 | Methods
206 | =======
207 |
208 | [Back to TOC](#table-of-contents)
209 | new
210 | ---
211 | `syntax: filter_obj = bloomd:new(host, port, timeout)`
212 |
213 | Create a new bloom filter object.
214 | * IN: the `host` is the bloomd's host, default is '127.0.0.1'.
215 | * IN: the `port` is the bloomd's port, default is 8673.
216 | * IN: the `timeout` is the timeout time in ms, default is 5000ms.
217 |
218 | create
219 | ---
220 | `syntax: ok, err = filter_obj:create(filter_name, capacity, prob, in_memory)`
221 |
222 | Create a new filter
223 | * IN: the `filter_name` is the name of the filter, and can contain the characters a-z, A-Z, 0-9, ., _.
224 | * IN: the `capacity` is provided the filter will be created to store at least that many items in the initial filter. default is 0.001.
225 | * IN: the `prob` is maximum false positive probability provided.
226 | * IN: the 'in_memory' is to force the filter not to be persisted to disk.
227 |
228 | list
229 | ---
230 | `syntax: ok, filters = filter_obj:list(filter_prefix)`
231 |
232 | List all filters or those matching a prefix.
233 | * OUT: the `ok` is list status.
234 | * OUT: the `filters` is a Lua table holding all the matched filter.
235 |
236 | ```lua
237 | for _,filter in ipairs(filters) do
238 | ngx.say(filter.name, ",", filter.probability, ",",
239 | filter.storage, ",", filter.capacity, ",",filter.size)
240 | end
241 | ```
242 |
243 | drop
244 | ---
245 | `syntax: ok, err = filter_obj:drop(filter_name)`
246 |
247 | Drop a filter (Deletes from disk). On Success Returns ok:true, err:'Done'
248 |
249 | close
250 | ---
251 | `syntax: ok, err = filter_obj:close(filter_name)`
252 |
253 | Close a filter (Unmaps from memory, but still accessible). On Success Returns ok:true, err:'Done'
254 |
255 |
256 | clear
257 | ---
258 | `syntax: ok, err = filter_obj:clear(filter_name)`
259 |
260 | Clear a filter from the lists (Removes memory, left on disk)
261 |
262 |
263 | check
264 | ---
265 | `syntax: ok, status = filter_obj:check(filter_name, key)`
266 |
267 | Check if a key is in a filter.
268 | * IN: the `status` is 'Yes'(`key` exists in filter) or 'No'(if `key` does not exists in filter).
269 |
270 | checks
271 | ---
272 | `syntax: ok, status = filter_obj:checks(filter_name, keys)`
273 |
274 | Check if a list of keys are in a filter
275 | * IN: the `keys` is a table that contains some keys.
276 | * OUT: the `status` is a table that contains each key's status('Yes' or 'No').
277 |
278 | set
279 | ---
280 | `syntax: ok, status = filter_obj:set(filter_name, key)`
281 |
282 | Set an item in a filter
283 | * OUT: the `status` is 'Yes'(`key` is successfully set to the filter) or 'No'(`key` exists in the filter).
284 |
285 |
286 | sets
287 | ---
288 | `syntax: ok, status = filter_obj:sets(filter_name, keys)`
289 |
290 | Set many items in a filter at once
291 | * IN: the `keys` is a table that contains some keys.
292 | * OUT: the `status` is a table that contains each key's set status('Yes' or 'No').
293 |
294 | info
295 | ---
296 | `syntax: ok, info = filter_obj:info(filter_name)`
297 |
298 | Get info about a filter
299 | * OUT: the `info` is a table like `{in_memory:1,set_misses:3,checks:8,capacity:100001, probability:0.001,page_outs:1,size:5,check_hits:5,
300 | storage:240141,page_ins:1,set_hits:5,check_misses:3,sets:8}`.
301 |
302 | flush
303 | ---
304 | `syntax: ok, err = filter_obj:flush(filter_name)`
305 |
306 | Flush a specified filter.
307 |
308 | [Back to TOC](#table-of-contents)
309 |
310 | Installation
311 | ============
312 |
313 | You need to compile [ngx_lua](https://github.com/chaoslawful/lua-nginx-module/tags) with your Nginx.
314 |
315 | You need to configure
316 | the [lua_package_path](https://github.com/chaoslawful/lua-nginx-module#lua_package_path) directive to
317 | add the path of your `lua-resty-bloomd` source tree to ngx_lua's Lua module search path, as in
318 |
319 | # nginx.conf
320 | http {
321 | lua_package_path "/path/to/lua-resty-bloomd/lib/?.lua;;";
322 | ...
323 | }
324 |
325 | and then load the library in Lua:
326 |
327 | bloomd = require "resty.bloomd"
328 |
329 | [Back to TOC](#table-of-contents)
330 |
331 | Authors
332 | =======
333 |
334 | Xiaojie Liu 。
335 |
336 | [Back to TOC](#table-of-contents)
337 |
338 | Copyright and License
339 | =====================
340 |
341 | This module is licensed under the BSD license.
342 |
343 | Copyright (C) 2015, by Xiaojie Liu
344 |
345 | All rights reserved.
346 |
347 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
348 |
349 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
350 |
351 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
352 |
353 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
354 |
355 | [Back to TOC](#table-of-contents)
356 |
357 |
--------------------------------------------------------------------------------
/lib/resty/bloomd.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) 2015 Xiaojie Liu (jie123108@163.com).
2 | -- lua-resty-bloomd - Is a ngx_lua client library to interface with bloomd servers
3 | -- https://github.com/armon/bloomd
4 |
5 | local ok, new_tab = pcall(require, "table.new")
6 | if not ok then
7 | new_tab = function (narr, nrec) return {} end
8 | end
9 |
10 | local ok, clear_tab = pcall(require, "table.clear")
11 | if not ok then
12 | clear_tab = function(tab) for k, _ in pairs(tab) do tab[k] = nil end end
13 | end
14 |
15 | local _M = new_tab(0, 2)
16 |
17 | _M._VERSION = '0.01'
18 |
19 | local function split_by_space(str)
20 | local result = {}
21 | for match in string.gmatch(str, "[^ ]+") do
22 | table.insert(result, match);
23 | end
24 | return result
25 | end
26 |
27 | local mt = { __index = _M }
28 |
29 | function _M:new(host, port, timeout)
30 | host = host or "127.0.0.1"
31 | port = port or 8673
32 | timeout = timeout or 1000*5
33 | return setmetatable({host=host, port=port, timeout=timeout}, mt)
34 | end
35 |
36 | function _M:_connect()
37 | local sock = ngx.socket.tcp()
38 | if self.timeout then
39 | sock:settimeout(self.timeout)
40 | end
41 | local ok, err = sock:connect(self.host, self.port)
42 | if not ok then
43 | sock:close()
44 | return nil, err
45 | end
46 |
47 | return sock
48 | end
49 |
50 | function _M:_setkeepalive(sock)
51 | if sock then
52 | sock:setkeepalive()
53 | sock = nil
54 | end
55 | end
56 |
57 | function _M:_request(sock, command, endval)
58 | assert(sock ~= nil, "socket not inited")
59 | assert(command ~= nil, "cmd is nil")
60 | local n, err = sock:send(command .. "\n")
61 | if err then
62 | return nil, err
63 | end
64 | if endval == nil then
65 | local line, err, partial = sock:receive('*l')
66 | return line, err, partial
67 | else
68 | local lines = {}
69 | for i=1, 10240 do
70 | local line, err, partial = sock:receive('*l')
71 | if err then
72 | table.insert(lines, partial)
73 | return nil, err, table.concat(lines, '\n')
74 | end
75 | table.insert(lines, line)
76 | if line == endval then
77 | break
78 | end
79 | end
80 | return lines, err
81 | end
82 | end
83 |
84 | function _M:_request_once(cmd, endval)
85 | local sock, err = self:_connect()
86 | if not sock then
87 | return nil, err
88 | end
89 | local line, err, partial = self:_request(sock, cmd, endval)
90 | self:_setkeepalive(sock)
91 | return line, err
92 | end
93 |
94 | function _M:create(filter_name, capacity, prob, in_memory)
95 | assert(filter_name ~= nil, "filter_name is nil")
96 |
97 | local cmds = {"create " .. filter_name}
98 | table.insert(cmds, cmd)
99 |
100 | if capacity and type(capacity) == 'number' then
101 | table.insert(cmds, "capacity=" .. tostring(capacity))
102 | end
103 | if prob and type(prob) == 'number' then
104 | table.insert(cmds, "prob=" .. tostring(prob))
105 | end
106 | if in_memory == 0 then
107 | in_memory = false
108 | end
109 | if in_memory then
110 | table.insert(cmds, "in_memory=1")
111 | end
112 |
113 | local cmd = table.concat(cmds, " ")
114 |
115 | local line, err = self:_request_once(cmd)
116 |
117 | if line == nil then
118 | return false, err
119 | end
120 | if line == "Done" or line == "Exists" then
121 | return true, line
122 | else
123 | return false, line
124 | end
125 | end
126 |
127 | function _M:_do_command1(cmd)
128 | assert(cmd ~= nil, "cmd is nil")
129 | local line, err = self:_request_once(cmd)
130 | if line == nil then
131 | return false, err
132 | end
133 | if line == "Done" then
134 | return true, line
135 | else
136 | return false, line
137 | end
138 | end
139 |
140 | function _M:drop(filter_name)
141 | assert(filter_name ~= nil, "filter_name is nil")
142 | local cmd = "drop " .. filter_name
143 | return self:_do_command1(cmd)
144 | end
145 |
146 | function _M:close(filter_name)
147 | assert(filter_name ~= nil, "filter_name is nil")
148 | local cmd = "close " .. filter_name
149 | return self:_do_command1(cmd)
150 | end
151 |
152 | function _M:clear(filter_name)
153 | assert(filter_name ~= nil, "filter_name is nil")
154 | local cmd = "clear " .. filter_name
155 | return self:_do_command1(cmd)
156 | end
157 |
158 | function _M:flush(filter_name)
159 | assert(filter_name ~= nil, "filter_name is nil")
160 | local cmd = "flush " .. filter_name
161 | return self:_do_command1(cmd)
162 | end
163 |
164 |
165 | function _M:_do_command2(cmd)
166 | assert(cmd ~= nil, "cmd is nil")
167 | local line, err = self:_request_once(cmd)
168 | if line == nil then
169 | return false, err
170 | end
171 | if line == "Yes" or line == "No" then
172 | return true, line
173 | else
174 | return false, line
175 | end
176 | end
177 |
178 | function _M:check(filter_name, key)
179 | assert(filter_name ~= nil, "filter_name is nil")
180 | assert(key ~= nil, "key is nil")
181 | local cmd = "c " .. filter_name .. " " .. tostring(key)
182 | return self:_do_command2(cmd)
183 | end
184 |
185 | function _M:set(filter_name, key)
186 | assert(filter_name ~= nil, "filter_name is nil")
187 | assert(key ~= nil, "key is nil")
188 | local cmd = "s " .. filter_name .. " " .. tostring(key)
189 | return self:_do_command2(cmd)
190 | end
191 |
192 | function _M:_do_command_multi(cmd)
193 | assert(cmd ~= nil, "cmd is nil")
194 | local line, err = self:_request_once(cmd)
195 | if line == nil then
196 | return false, err
197 | end
198 | if line == "Filter does not exist" then
199 | return false, line
200 | else
201 | local result = split_by_space(line)
202 | return true, result
203 | end
204 | end
205 |
206 | function _M:checks(filter_name, keys)
207 | assert(filter_name ~= nil, "filter_name is nil")
208 | assert(type(keys) == 'table', "keys must be a 'table'")
209 | local cmd = "m " .. filter_name .. " " .. table.concat(keys, " ")
210 | return self:_do_command_multi(cmd)
211 | end
212 |
213 | function _M:sets(filter_name, keys)
214 | assert(filter_name ~= nil, "filter_name is nil")
215 | assert(type(keys) == 'table', "keys must be a 'table'")
216 | local cmd = "b " .. filter_name .. " " .. table.concat(keys, " ")
217 | return self:_do_command_multi(cmd)
218 | end
219 |
220 | function _M:_do_command_list(cmd)
221 | assert(cmd ~= nil, "cmd is nil")
222 | local lines, err = self:_request_once(cmd, "END")
223 | if lines == nil then
224 | return false, err
225 | end
226 | assert(type(lines) == 'table')
227 | local list = {}
228 | for _,line in ipairs(lines) do
229 | if line ~= 'START' and line ~= 'END' then
230 | table.insert(list, line)
231 | end
232 | end
233 | return true, list
234 | end
235 |
236 | function _M:info(filter_name)
237 | assert(filter_name ~= nil, "filter_name is nil")
238 | local cmd = "info " .. filter_name
239 | local ok, list = self:_do_command_list(cmd)
240 | if not ok then
241 | return ok, list
242 | end
243 | local infos = {}
244 | for _, line in ipairs(list) do
245 | local item = split_by_space(line)
246 | if #item == 2 then
247 | infos[item[1]] = tonumber(item[2])
248 | else
249 | ngx.log(ngx.ERR, "invalid line [", line, "]")
250 | end
251 | end
252 | return true, infos
253 | end
254 |
255 | function _M:list(prefix)
256 | local cmd = "list"
257 | if prefix then
258 | cmd = cmd .. " " .. prefix
259 | end
260 | local ok, list = self:_do_command_list(cmd)
261 | if not ok then
262 | return ok, list
263 | end
264 | local filters = {}
265 | for _, line in ipairs(list) do
266 | local item = split_by_space(line)
267 | if #item == 5 then
268 | -- filter_name probability storage capacity size
269 | local filter_info = {}
270 | filter_info['name'] = item[1]
271 | filter_info['probability'] = tonumber(item[2])
272 | filter_info['storage'] = tonumber(item[3])
273 | filter_info['capacity'] = tonumber(item[4])
274 | filter_info['size'] = tonumber(item[5])
275 |
276 | table.insert(filters, filter_info)
277 | else
278 | ngx.log(ngx.ERR, "invalid line [", line, "]")
279 | end
280 | end
281 | return true, filters
282 | end
283 |
284 | return _M
285 |
--------------------------------------------------------------------------------
/t/test.lua:
--------------------------------------------------------------------------------
1 | local bloomd = require("resty.bloomd")
2 |
3 | local function debug(name, ok, err)
4 | if type(err) == 'table' then
5 | local t = {}
6 | for k, v in pairs(err) do
7 | table.insert(t, k .. ":" .. tostring(v))
8 | end
9 | err = table.concat(t, ",")
10 | end
11 | ngx.say(string.format("%15s -- ok: %5s, err: %s", name, tostring(ok), tostring(err)))
12 | end
13 | -- create a new instance and connect to the bloomd(127.0.0.1:8673)
14 | local filter_obj = bloomd:new("127.0.0.1", 8673, 2000)
15 | local function test_main()
16 | local filter_name = "my_filter"
17 | local capacity = 100001
18 | local probability = 0.001
19 | -- create a filter named filter_name
20 | local ok, err = filter_obj:create(filter_name, capacity, probability)
21 | debug("create-new", ok, err)
22 | assert(ok == true)
23 | -- assert(err == "Done", "err ~= 'Done'")
24 |
25 | -- create a filter, the name is exist
26 | local ok, err = filter_obj:create(filter_name, capacity, probability)
27 | debug("create-exist", ok, err)
28 | assert(ok == true)
29 | assert(err == "Exists")
30 |
31 | -- set a key, New
32 | local ok, err = filter_obj:set(filter_name, 'my_key')
33 | debug("set-new", ok, err)
34 | assert(ok==true)
35 | assert(err == "Yes")
36 |
37 | -- set a key, Exist
38 | local ok, err = filter_obj:set(filter_name, 'my_key')
39 | debug("set-exist", ok, err)
40 | assert(ok==true)
41 | assert(err == "No")
42 |
43 | -- check a key, Exist
44 | local ok, err = filter_obj:check(filter_name, 'my_key')
45 | debug("check-exist", ok, err)
46 | assert(ok==true)
47 | assert(err == "Yes")
48 |
49 | -- check a key, Not Exist
50 | local ok, err = filter_obj:check(filter_name, 'this_key_not_exist')
51 | debug("check-not-exist", ok, err)
52 | assert(ok==true)
53 | assert(err == "No")
54 |
55 | -- flush a filter
56 | local ok, err = filter_obj:flush(filter_name)
57 | debug("flush", ok, err)
58 | assert(ok==true)
59 | assert(err == "Done")
60 |
61 | -- close a bloom filter
62 | local ok, err = filter_obj:close(filter_name)
63 | debug("close", ok, err)
64 | assert(ok==true)
65 | assert(err == "Done")
66 |
67 | -- check a key, Exist
68 | local ok, err = filter_obj:check(filter_name, 'my_key')
69 | debug("check-exist", ok, err)
70 | assert(ok==true)
71 | assert(err == "Yes")
72 |
73 |
74 | filter_obj:create("my_filter3", capacity, 0.001)
75 | -- list all filter
76 | local ok, filters = filter_obj:list(filter_name)
77 | debug("list", ok, filters)
78 | assert(ok==true)
79 | assert(type(filters)=='table' and #filters==2)
80 | for _,filter in ipairs(filters) do
81 | if filter.name == filter_name then
82 | assert(filter.size == 1)
83 | end
84 | end
85 | filter_obj:drop('my_filter3')
86 |
87 | -- Set many items in a filter at once(bulk command)
88 | local ok, status = filter_obj:sets(filter_name, {"a", "b", "c"})
89 | assert(ok)
90 | assert(type(status)=='table')
91 | err = table.concat(status, ' ')
92 | debug("sets", ok, err)
93 | assert(err == "Yes Yes Yes")
94 |
95 | local ok, status = filter_obj:sets(filter_name, {"a", "b", "d"})
96 | assert(ok)
97 | assert(type(status)=='table')
98 | err = table.concat(status, ' ')
99 | debug("sets", ok, err)
100 | assert(err == "No No Yes")
101 |
102 | -- Checks if a list of keys are in a filter
103 | local ok, status = filter_obj:checks(filter_name, {"a", "x", "c", "d", "e"})
104 | assert(ok)
105 | assert(type(status)=='table')
106 | err = table.concat(status, ' ')
107 | debug("checks", ok, err)
108 | assert(err == "Yes No Yes Yes No")
109 |
110 |
111 | -- Gets info about a filter
112 | local ok, info = filter_obj:info(filter_name)
113 | debug("info", ok, info)
114 | assert(ok)
115 | assert(type(info)=='table')
116 | assert(info.capacity == capacity)
117 | assert(info.probability == probability)
118 | assert(info.size == 5)
119 |
120 | -- drop a filter
121 | local ok, err = filter_obj:drop(filter_name)
122 | debug("drop", ok, err)
123 | assert(ok==true)
124 | assert(err == "Done")
125 |
126 |
127 | -- Test filter not exist
128 | local ok, err = filter_obj:drop(filter_name)
129 | debug("drop-not-exist", ok, err)
130 | assert(ok==false)
131 | assert(err == "Filter does not exist")
132 |
133 |
134 | -- create, close and clear a bloom filter, my_filter2 is still in disk.
135 | local ok, err = filter_obj:create("my_filter2", 10000*20, 0.001)
136 | debug("create-new", ok, err)
137 | assert(ok == true)
138 | assert(err == "Done", "err ~= 'Done'")
139 | local ok, err = filter_obj:close("my_filter2")
140 | debug("close", ok, err)
141 | assert(ok==true)
142 | assert(err == "Done")
143 | local ok, err = filter_obj:clear("my_filter2")
144 | debug("clear", ok, err)
145 | assert(ok==true)
146 | assert(err == "Done")
147 |
148 | ngx.say("--------- all test ok --------------")
149 | end
150 | local ok, err = pcall(test_main)
151 | if not ok then
152 | filter_obj:close("my_filter")
153 | filter_obj:close("my_filter2")
154 | filter_obj:close("my_filter3")
155 | assert(ok, err)
156 | end
157 |
--------------------------------------------------------------------------------