├── .buildpath
├── .gitignore
├── .project
├── .settings
└── org.eclipse.ldt.prefs
├── .travis.yml
├── LICENSE
├── README.markdown
├── build.sh
├── conf
├── nginx.conf
├── zoo.conf
└── zoo_server.conf
├── config
├── html
└── zoo
│ ├── css
│ ├── bootstrap.min.css
│ ├── index.css
│ └── layout.css
│ ├── img
│ └── d.png
│ ├── index.html
│ └── js
│ ├── index.js
│ ├── jquery.json2html.js
│ ├── jquery.min.js
│ └── json2html.js
├── lua
├── zoo.lua
└── zoo
│ └── api.lua
├── ngx_zookeeper_lua.h
├── ngx_zookeeper_lua_module.c
├── patches
└── lua-cjson-Makefile.patch
├── scripts
├── restart.sh
├── start.sh
└── stop.sh
├── t
├── directives.t
├── inactive.t
├── lua
├── operations.t
├── watch.t
└── zoo.jmx
├── tests.sh
└── zoo_ui.png
/.buildpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | src
2 | build
3 | install
4 | t/servroot
5 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | ngx_zookeeper_lua
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.dltk.core.scriptbuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.ldt.nature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.ldt.prefs:
--------------------------------------------------------------------------------
1 | Grammar__default_id=lua-5.2
2 | eclipse.preferences.version=1
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 |
3 | before_install:
4 | - sudo apt-get -y install default-jdk ant
5 |
6 | compiler:
7 | - gcc
8 |
9 | script:
10 | - ./build.sh build
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 2-Clause License
2 |
3 | Copyright (c) 2016, Aleksey Konovkin
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | Name
2 | ====
3 |
4 | ngx_zookeeper_lua - Lua bindings to interract with Zookeeper.
5 |
6 | Build status
7 | ============
8 | [](https://travis-ci.org/ZigzagAK/ngx_zookeeper_lua)
9 |
10 | Table of Contents
11 | =================
12 |
13 | * [Name](#name)
14 | * [Status](#status)
15 | * [Synopsis](#synopsis)
16 | * [Description](#description)
17 | * [Install](#install)
18 | * [Simple UI](#simple-ui)
19 | * [Configuration directives](#configuration-directives)
20 | * [Base methods](#methods)
21 | * [connected](#connected)
22 | * [get](#get)
23 | * [childrens](#childrens)
24 | * [set](#set)
25 | * [create](#create)
26 | * [delete](#delete)
27 | * [delete_recursive](#delete_recursive)
28 | * [tree](#tree)
29 | * [watch](#watch)
30 | * [watch_path](#watch_path)
31 | * [watcher_exists](#watcher_exists)
32 | * [unwatch](#unwatch)
33 | * [Additional API](#additional-api)
34 | * [api.tree](#api-tree)
35 | * [api.import](#api-import)
36 |
37 | Status
38 | ======
39 |
40 | This library is production ready.
41 |
42 | Description
43 | ===========
44 |
45 | This module provides Lua bindings to interract with Zookeeper.
46 |
47 | [Back to TOC](#table-of-contents)
48 |
49 | Install
50 | =======
51 |
52 | Build nginx with Zookeeper support.
53 | All dependencies are downloaded automaticaly.
54 |
55 | ```
56 | git clone git@github.com:ZigzagAK/ngx_zookeeper_lua.git
57 | cd ngx_zookeeper_lua
58 | ./build.sh
59 | ```
60 |
61 | Archive will be placed in the `install` folder after successful build.
62 |
63 | [Back to TOC](#table-of-contents)
64 |
65 | Synopsis
66 | ========
67 |
68 | ```nginx
69 | http {
70 | zookeeper 127.0.0.1:2181;
71 | zookeeper_log_level debug;
72 | zookeeper_recv_timeout 5000;
73 | zookeeper_ephemeral_node /services/nginx 127.0.0.1 "nginx";
74 |
75 | lua_shared_dict config 64k;
76 | lua_shared_dict zoo_cache 10m;
77 |
78 | init_by_lua_block {
79 | ngx.shared.config:set("zoo.cache.on", true)
80 | ngx.shared.config:set("zoo.cache.ttl", 60)
81 |
82 | ngx.shared.config:set("zoo.cache.path.ttl", '[' ..
83 | '{ "path" : "/services/.*", "ttl" : 0 }' ..
84 | ']')
85 | }
86 |
87 | init_worker_by_lua_block {
88 | assert(ngx.timer.at(1, function()
89 | local zoo = require "zoo"
90 | local cjson = require "cjson"
91 |
92 | zoo.delete_recursive("/watched1")
93 | zoo.delete_recursive("/watched2")
94 |
95 | zoo.create("/watched1")
96 | zoo.create("/watched2")
97 |
98 | local function on_event(ctx)
99 | local data = assert(zoo.watch(ctx.path, ctx.watcher_type, on_event, ctx))
100 | ngx.log(ngx.INFO, "on_event: ", ctx.path, "=", cjson.encode(data))
101 | end
102 |
103 | on_event {
104 | watcher_type = zoo.WatcherType.DATA,
105 | path = "/watched1"
106 | }
107 |
108 | on_event {
109 | watcher_type = zoo.WatcherType.DATA,
110 | path = "/watched2"
111 | }
112 |
113 | on_event {
114 | watcher_type = zoo.WatcherType.CHILDREN,
115 | path = "/watched1"
116 | }
117 |
118 | on_event {
119 | watcher_type = zoo.WatcherType.CHILDREN,
120 | path = "/watched2"
121 | }
122 |
123 | local stop
124 |
125 | assert(ngx.timer.at(60, function()
126 | assert(zoo.unwatch("/watched1", zoo.WatcherType.DATA))
127 | assert(zoo.unwatch("/watched1", zoo.WatcherType.CHILDREN))
128 | assert(zoo.unwatch("/watched2", zoo.WatcherType.DATA))
129 | assert(zoo.unwatch("/watched2", zoo.WatcherType.CHILDREN))
130 | ngx.log(ngx.INFO, "unwatch")
131 | stop = ngx.now() + 10
132 | end))
133 |
134 | local i = 0
135 |
136 | local function change(premature)
137 | if premature or (stop and stop < ngx.now()) then
138 | return
139 | end
140 |
141 | pcall(function()
142 | if zoo.connected() then
143 | i = i + 1
144 |
145 | assert(zoo.set("/watched1", i))
146 | assert(zoo.set("/watched2", i))
147 |
148 | if i % 2 == 1 then
149 | assert(zoo.create("/watched1/1"))
150 | assert(zoo.create("/watched2/1"))
151 | else
152 | assert(zoo.delete("/watched1/1"))
153 | assert(zoo.delete("/watched2/1"))
154 | end
155 |
156 | ngx.log(ngx.INFO, "update")
157 | end
158 | end)
159 |
160 | assert(ngx.timer.at(1, change))
161 | end
162 |
163 | assert(ngx.timer.at(1, change))
164 | end))
165 | }
166 |
167 | server {
168 | listen 8000;
169 | zookeeper_register_port /services/nginx/8000 8000 "nginx-8080";
170 |
171 | location / {
172 | return 200 '8000';
173 | }
174 | }
175 |
176 | server {
177 | listen 8001;
178 |
179 | location /a {
180 | zookeeper_ephemeral_node /services/nginx/8001/a 127.0.0.1:8001;
181 | return 200 '8001:a';
182 | }
183 |
184 | location /b {
185 | zookeeper_ephemeral_node /services/nginx/8001/b 127.0.0.1:8001;
186 | return 200 '8001:b';
187 | }
188 | }
189 |
190 | server {
191 | listen 12181;
192 |
193 | include mime.types;
194 | default_type application/json;
195 |
196 | root html/zoo;
197 |
198 | index index.html;
199 |
200 | server_name zoo;
201 |
202 | location = /get {
203 | content_by_lua_block {
204 | local zoo = require "zoo"
205 | local cjson = require "cjson"
206 | local value, stat, err = zoo.get(ngx.var.arg_znode)
207 | ngx.say(cjson.encode(value and { value = value, stat = stat } or { error = err }))
208 | }
209 | }
210 |
211 | location = /childrens {
212 | content_by_lua_block {
213 | local zoo = require "zoo"
214 | local cjson = require "cjson"
215 | local childs, err = zoo.childrens(ngx.var.arg_znode)
216 | ngx.say(cjson.encode(childs and childs or { error = err }))
217 | }
218 | }
219 |
220 | location = /set {
221 | content_by_lua_block {
222 | local zoo = require "zoo"
223 | local cjson = require "cjson"
224 | local stat, err = zoo.set(ngx.var.arg_znode, ngx.var.arg_value, ngx.var.arg_version)
225 | ngx.say(cjson.encode(stat and { value = ngx.var.arg_value, stat = stat } or { error = err }))
226 | }
227 | }
228 |
229 | location = /create {
230 | content_by_lua_block {
231 | local zoo = require "zoo"
232 | local cjson = require "cjson"
233 | local result, err = zoo.create(ngx.var.arg_znode, ngx.var.arg_value)
234 | ngx.say(cjson.encode(result and { znode = result } or { error = err }))
235 | }
236 | }
237 |
238 | location = /delete {
239 | content_by_lua_block {
240 | local zoo = require "zoo"
241 | local cjson = require "cjson"
242 | local ok, err = zoo.delete(ngx.var.arg_znode)
243 | ngx.say(cjson.encode(ok and { znode = "deleted" } or { error = err }))
244 | }
245 | }
246 |
247 | location = /tree {
248 | content_by_lua_block {
249 | local api = require "zoo.api"
250 | local cjson = require "cjson"
251 | ngx.say(cjson.encode(api.tree(ngx.var.arg_znode,
252 | ngx.var.arg_stat and ngx.var.arg_stat:match("[1yY]"))))
253 | }
254 | }
255 |
256 | location = /import {
257 | content_by_lua_block {
258 | local api = require "zoo.api"
259 |
260 | local method = ngx.req.get_method()
261 | if method ~= "POST" and method ~= "PUT" then
262 | ngx.exit(ngx.HTTP_BAD_REQUEST)
263 | end
264 |
265 | local content_type = ngx.req.get_headers().content_type
266 |
267 | if not content_type or content_type:lower() ~= "application/json" then
268 | ngx.exit(ngx.HTTP_BAD_REQUEST)
269 | end
270 |
271 | ngx.req.read_body()
272 | local data = ngx.req.get_body_data()
273 |
274 | local ok, err = api.import(ngx.var.arg_znode or "/", data)
275 | if ok then
276 | ngx.say("Imported")
277 | else
278 | ngx.say(err)
279 | end
280 | }
281 | }
282 | }
283 | }
284 | ```
285 |
286 | **Watch tree**
287 |
288 | ```nginx
289 | location / {
290 | content_by_lua_block {
291 | local zoo = require "zoo"
292 | local cjson = require "cjson"
293 |
294 | local function on_event(ctx, ev)
295 | local data = assert(zoo.watch(ev.path, ev.watcher_type, on_event, ctx))
296 | ngx.log(ngx.INFO, "on_event: ", ev.path, ", type=", ev.watcher_type, " :", cjson.encode(data))
297 | if ev.watcher_type == zoo.WatcherType.CHILDREN then
298 | for _,c in ipairs(data) do
299 | if not zoo.watcher_exists(ev.path .. "/" .. c) then
300 | assert(zoo.watch_path(ev.path .. "/" .. c, on_event, ctx))
301 | end
302 | end
303 | ctx.data[ev.path] = data
304 | end
305 | end
306 |
307 | local ctx = { ["/test"] = assert(zoo.childrens("/test")) }
308 | assert(zoo.watch_path("/test", on_event, ctx))
309 | }
310 | }
311 | ```
312 |
313 | [Back to TOC](#table-of-contents)
314 |
315 | Simple UI
316 | ========================
317 | UI displays Zookeeper content.
318 | Available on `http://127.0.0.1:4444`
319 |
320 | 
321 |
322 | [Back to TOC](#table-of-contents)
323 |
324 | Configuration directives
325 | ========================
326 |
327 | zookeeper
328 | --------------
329 | * **syntax**: `zookeeper `
330 | * **default**: `none`
331 | * **context**: `http`
332 |
333 | Configure Zookeeper servers.
334 |
335 | zookeeper_log_level
336 | --------------
337 | * **syntax**: `zookeeper_log_level `
338 | * **default**: `error`
339 | * **values**: `error, warn, info, debug`
340 | * **context**: `http`
341 |
342 | Configure Zookeeper log level.
343 |
344 | zookeeper_recv_timeout
345 | --------------
346 | * **syntax**: `zookeeper_recv_timeout `
347 | * **default**: `10000`
348 | * **values**: `1-60000`
349 | * **context**: `http`
350 |
351 | Configure Zookeeper socket recv timeout.
352 |
353 | zookeeper_node
354 | --------------
355 | * **syntax**: `zookeeper_node [data]`
356 | * **default**: `none`
357 | * **context**: `http,server,location`
358 |
359 | Create persistent Zookeeper node.
360 |
361 | zookeeper_ephemeral_node
362 | --------------
363 | * **syntax**: `zookeeper_ephemeral_node [data]`
364 | * **default**: `none`
365 | * **context**: `http,server,location`
366 |
367 | Register nginx in Zookeeper ephemeral node.
368 |
369 | zookeeper_register_port
370 | --------------
371 | * **syntax**: `zookeeper_register_port [data]`
372 | * **default**: `none`
373 | * **context**: `server`
374 |
375 | Register nginx in Zookeeper ephemeral node with host_IPv4:port.
376 |
377 | zookeeper_inactive_time
378 | --------------
379 | * **syntax**: `zookeeper_inactive_time `
380 | * **default**: `none`
381 | * **context**: `http`
382 |
383 | Disconnect from zookeeper after inactive period.
384 |
385 | [Back to TOC](#table-of-contents)
386 |
387 | Methods
388 | =======
389 |
390 | connected
391 | ---------
392 | **syntax:** `connected = zoo.connected()`
393 |
394 | **context:** **_by_lua**
395 |
396 | Return status of Zookeeper connection.
397 |
398 | Returns true or false.
399 |
400 | get
401 | ---
402 | **syntax:** `value, stat, err = zoo.get(znode, nocache)`
403 |
404 | **context:** **_by_lua**
405 |
406 | Get value of the `znode` and znode information.
407 | `stat`: { czxid, mzxid, ctime, mtime, version, cversion, aversion, ephemeralOwner, dataLength, numChildren, pzxid }
408 |
409 | `nocache=true`: bypass cache.
410 |
411 | Returns value on success, or nil and a string describing an error otherwise.
412 |
413 | childrens
414 | ---------
415 | **syntax:** `childs, err = zoo.childrens(znode, nocache)`
416 |
417 | **context:** **_by_lua**
418 |
419 | Get child znode's names of the `znode`.
420 |
421 | `nocache=true`: bypass cache.
422 |
423 | Returns table with znode's names on success, or nil and a string describing an error otherwise.
424 |
425 | set
426 | ---
427 | **syntax:** `result, err = zoo.set(znode, value, version)`
428 |
429 | **context:** **_by_lua**
430 |
431 | Set value of the `znode`. Version may be nil (no version check). `value` may be a table (converted to json on store).
432 |
433 | Returns znode information on success, or nil and a string describing an error otherwise.
434 |
435 | create
436 | ------
437 | **syntax:** `result, err = zoo.create(znode, value, mode)`
438 |
439 | **context:** **_by_lua**
440 |
441 | Create the `znode` with initial `value`.
442 | `mode`: flags.ZOO_EPHEMERAL, flags.ZOO_SEQUENCE
443 |
444 | Returns new `znode` path on success, or nil and a string describing an error otherwise.
445 |
446 | delete
447 | ------
448 | **syntax:** `ok, err = zoo.delete(znode)`
449 |
450 | **context:** **_by_lua**
451 |
452 | Delete the `znode`.
453 |
454 | Returns true on success, or false and a string describing an error otherwise.
455 |
456 | [Back to TOC](#table-of-contents)
457 |
458 | delete_recursive
459 | ----------------
460 | **syntax:** `ok, err = zoo.delete_recursive(znode)`
461 |
462 | **context:** **_by_lua**
463 |
464 | Delete the `znode` with all childs.
465 |
466 | Returns true on success, or false and a string describing an error otherwise.
467 |
468 | [Back to TOC](#table-of-contents)
469 |
470 | tree
471 | ----
472 | **syntax:** `data, err = zoo.tree(znode, need_stat)`
473 |
474 | **context:** **_by_lua**
475 |
476 | Returns subtree of znode, or false and a string describing an error otherwise
477 |
478 | watch
479 | ----------------
480 | **syntax:** `data, err = zoo.watch(znode, watch_type, callback, ctx)`
481 |
482 | **context:** **_by_lua**
483 |
484 | Get value or childrens and setup wather for `znode`.
485 |
486 | watcher_type MUST be one of `zoo.WatcherType.CHILDREN, zoo.WatcherType.DATA`.
487 |
488 | Returns value/childrens on success, or nil and a string describing an error otherwise.
489 |
490 | See [Synopsis](#synopsis) for details.
491 |
492 | [Back to TOC](#table-of-contents)
493 |
494 | watch_path
495 | ----------------
496 | **syntax:** `tree, err = zoo.watch_path(znode, callback, ctx)`
497 |
498 | **context:** **_by_lua**
499 |
500 | Get full tree and setup watchers whole tree.
501 |
502 | Return tree on success, or nil and a string describing an error otherwise.
503 |
504 | See [Synopsis](#synopsis) for details.
505 |
506 | [Back to TOC](#table-of-contents)
507 |
508 | watcher_exists
509 | ----------------
510 | **syntax:** `flag = zoo.watcher_exists(znode, watch_type)`
511 |
512 | **context:** **_by_lua**
513 |
514 | Check for watcher exists for `znode`.
515 |
516 | watcher_type MUST be one of `zoo.WatcherType.CHILDREN, zoo.WatcherType.DATA` or MAY be nil.
517 |
518 | Returns true or false.
519 |
520 | See [Synopsis](#synopsis) for details.
521 |
522 | [Back to TOC](#table-of-contents)
523 |
524 | unwatch
525 | ----------------
526 | **syntax:** `data, err = zoo.unwatch(znode, watch_type)`
527 |
528 | **context:** **_by_lua**
529 |
530 | Remove watcher for `znode`.
531 |
532 | watcher_type MUST be one of `zoo.WatcherType.CHILDREN, zoo.WatcherType.DATA`.
533 |
534 | Returns true on success, or nil and a string describing an error otherwise.
535 |
536 | See [Synopsis](#synopsis) for details.
537 |
538 | [Back to TOC](#table-of-contents)
539 |
540 | Additional API
541 | ==============
542 |
543 | `local api = require "zoo.api"`
544 |
545 | api tree
546 | --------
547 | **syntax:** `r = api.tree(znode, need_stat)`
548 |
549 | **context:** **_by_lua**
550 |
551 | Returns subtree of znode, or false and a string describing an error otherwise
552 |
553 | api import
554 | ----------
555 | **syntax:** `r = api.import(root, json)`
556 |
557 | **context:** **_by_lua**
558 |
559 | Import znodes from json (format - api.tree). Overwrite existing values.
560 |
561 | Returns true on success, or false and a string describing an error otherwise.
562 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright, Aleksey Konovkin (alkon2000@mail.ru)
4 | # BSD license type
5 |
6 | if [ "$1" == "" ]; then
7 | echo "build.sh "
8 | exit 0
9 | fi
10 |
11 | download=0
12 | download_only=0
13 | download_all=0
14 | build_deps=0
15 | clean_all=0
16 | compile=0
17 | build_only=0
18 | make_clean=0
19 |
20 | DIR="$(pwd)"
21 | DIAG_DIR="diag"
22 | VCS_PATH=${DIR%/*/*}
23 |
24 | VERSION="1.16.0"
25 | ZOO_VERSION="3.5.8"
26 | PCRE_VERSION="8.40"
27 | ZLIB_VERSION="1.2.11"
28 |
29 | SUFFIX=""
30 |
31 | if [ "$BUILD_DIR" == "" ]; then
32 | BUILD_DIR="$DIR/build"
33 | fi
34 |
35 | if [ "$INSTALL_DIR" == "" ]; then
36 | INSTALL_DIR="$DIR/install"
37 | fi
38 |
39 | if [ "$ERR_LOG" == "" ]; then
40 | ERR_LOG=$BUILD_DIR/error.log
41 | else
42 | ERR_LOG=$BUILD_DIR/$ERR_LOG
43 | fi
44 |
45 | if [ "$BUILD_LOG" == "" ]; then
46 | BUILD_LOG=$BUILD_DIR/build.log
47 | else
48 | BUILD_LOG=$BUILD_DIR/$BUILD_LOG
49 | fi
50 |
51 | [ -e "$BUILD_DIR" ] || mkdir -p $BUILD_DIR
52 |
53 | export ZOO_PREFIX="$BUILD_DIR/deps/zookeeper"
54 | export JIT_PREFIX="$BUILD_DIR/deps/luajit"
55 | export ZLIB_PREFIX="$BUILD_DIR/deps/zlib"
56 | export PCRE_PREFIX="$BUILD_DIR/deps/pcre"
57 |
58 | export LUAJIT_INC="$JIT_PREFIX/usr/local/include/luajit-2.1"
59 | export LUAJIT_LIB="$JIT_PREFIX/usr/local/lib"
60 | export LUAJIT_BIN="$JIT_PREFIX/usr/local/bin/luajit-$LUAJIT_VERSION"
61 |
62 | export LD_LIBRARY_PATH="-L$PCRE_PREFIX/lib:$LUAJIT_LIB:$ZOO_PREFIX/lib:$ZLIB_PREFIX/lib"
63 |
64 | ADDITIONAL_INCLUDES="-I$PCRE_PREFIX/include -I$ZLIB_PREFIX/include"
65 | ADDITIONAL_LIBS="-L$PCRE_PREFIX/lib -L$ZLIB_PREFIX/lib"
66 |
67 | function clean() {
68 | rm -rf install 2>>$ERR_LOG
69 | if [ $clean_all -eq 1 ]; then
70 | rm -rf $BUILD_DIR 2>>$ERR_LOG
71 | else
72 | rm -rf $(ls -1d $BUILD_DIR/* 2>>$ERR_LOG | grep -v deps) 2>>$ERR_LOG
73 | fi
74 | if [ $download_all -eq 1 ]; then
75 | rm -rf src 2>>$ERR_LOG
76 | fi
77 | }
78 |
79 | doclean=0
80 | dobuild=0
81 |
82 | for i in "$@"
83 | do
84 | if [ "$i" == "download" ]; then
85 | download=1
86 | fi
87 |
88 | if [ "$i" == "download_all" ]; then
89 | download=1
90 | download_all=1
91 | fi
92 |
93 | if [ "$i" == "clean_all" ]; then
94 | clean_all=1
95 | doclean=1
96 | fi
97 |
98 | if [ "$i" == "build" ]; then
99 | dobuild=1
100 | fi
101 |
102 | if [ "$i" == "build_only" ]; then
103 | dobuild=1
104 | build_only=1
105 | fi
106 |
107 | if [ "$i" == "clean" ]; then
108 | doclean=1
109 | fi
110 |
111 | if [ "$i" == "compile" ]; then
112 | compile=1
113 | fi
114 | done
115 |
116 | if [ $doclean -eq 1 ]; then
117 | clean
118 | fi
119 |
120 | if [ $download -eq 1 ] && [ $dobuild -eq 0 ]; then
121 | download_only=1
122 | fi
123 |
124 | if [ $download -eq 0 ] && [ $dobuild -eq 0 ]; then
125 | if [ $make_components -eq 0 ]; then
126 | exit 0
127 | fi
128 | fi
129 |
130 |
131 | current_os=`uname`
132 | if [ "$current_os" = "Linux" ]; then
133 | platform="linux"
134 | arch=`uname -p`
135 | shared="so"
136 | if [ -e /etc/redhat-release ]; then
137 | vendor='redhat'
138 | ver=`cat /etc/redhat-release | sed -e 's#[^0-9]##g' -e 's#7[0-2]#73#'`
139 | if [ $ver -lt 50 ]; then
140 | os_release='4.0'
141 | elif [ $ver -lt 60 ]; then
142 | os_release='5.0'
143 | elif [ $ver -lt 70 ]; then
144 | os_release='6.0'
145 | else
146 | os_release='7.0'
147 | fi
148 | if [ "$arch" != "x86_64" ]; then
149 | arch='i686'
150 | fi
151 | DISTR_NAME=$vendor-$platform-$os_release-$arch
152 | else
153 | vendor=$(uname -r)
154 | DISTR_NAME=$vendor-$platform-$arch
155 | fi
156 | fi
157 | if [ "$current_os" = "Darwin" ]; then
158 | platform="macos"
159 | arch=`uname -m`
160 | vendor="apple"
161 | shared="dylib"
162 | CFLAGS="-arch x86_64"
163 | DISTR_NAME=$vendor-$platform-$arch
164 | fi
165 |
166 | case $platform in
167 | linux)
168 | # platform has been recognized
169 | ;;
170 | macos)
171 | # platform has been recognized
172 | ;;
173 | *)
174 | echo "I do not recognize the platform '$platform'." | tee -a $BUILD_LOG
175 | exit 1;;
176 | esac
177 |
178 | if [ -z "$BUILD_VERSION" ]; then
179 | BUILD_VERSION="develop"
180 | fi
181 |
182 | function build_pcre() {
183 | echo "Build PCRE" | tee -a $BUILD_LOG
184 | cd pcre-$PCRE_VERSION
185 | ./configure --prefix="$PCRE_PREFIX" --libdir="$PCRE_PREFIX/lib" >> $BUILD_LOG 2>>$ERR_LOG
186 | make -j 8 >> $BUILD_LOG 2>>$ERR_LOG
187 | r=$?
188 | if [ $r -ne 0 ]; then
189 | exit $r
190 | fi
191 | make install >> $BUILD_LOG 2>>$ERR_LOG
192 | cd ..
193 | }
194 |
195 | function build_zlib() {
196 | echo "Build ZLIB" | tee -a $BUILD_LOG
197 | cd zlib-$ZLIB_VERSION
198 | ./configure --prefix="$ZLIB_PREFIX" --libdir="$ZLIB_PREFIX/lib" >> $BUILD_LOG 2>>$ERR_LOG
199 | make -j 8 >> $BUILD_LOG 2>>$ERR_LOG
200 | r=$?
201 | if [ $r -ne 0 ]; then
202 | exit $r
203 | fi
204 | make install >> $BUILD_LOG 2>>$ERR_LOG
205 | cd ..
206 | }
207 |
208 | function build_zoo() {
209 | echo "Build Zookeeper" | tee -a $BUILD_LOG
210 | cd apache-zookeeper-$ZOO_VERSION
211 | ant compile_jute
212 | cd zookeeper-client/zookeeper-client-c
213 | autoreconf -if >> $BUILD_LOG 2>>$ERR_LOG
214 | ./configure --without-cppunit --prefix="$ZOO_PREFIX" --enable-shared --disable-static --libdir "$ZOO_PREFIX/lib" >> $BUILD_LOG 2>>$ERR_LOG
215 | make -j 8 >> $BUILD_LOG 2>>$ERR_LOG
216 | r=$?
217 | if [ $r -ne 0 ]; then
218 | exit $r
219 | fi
220 | make install >> $BUILD_LOG 2>>$ERR_LOG
221 | cd ../../..
222 | }
223 |
224 | function build_luajit() {
225 | echo "Build luajit" | tee -a $BUILD_LOG
226 | cd luajit2
227 | make >> $BUILD_LOG 2>>$ERR_LOG
228 | r=$?
229 | if [ $r -ne 0 ]; then
230 | exit $r
231 | fi
232 | DESTDIR="$JIT_PREFIX" make install >> $BUILD_LOG 2>>$ERR_LOG
233 | cd ..
234 | }
235 |
236 | function build_cJSON() {
237 | echo "Build cjson" | tee -a $BUILD_LOG
238 | cd lua-cjson
239 | LUA_INCLUDE_DIR="$JIT_PREFIX/usr/local/include/luajit-2.1" LDFLAGS="-L$JIT_PREFIX/usr/local/lib -lluajit-5.1" make >> $BUILD_LOG 2>>$ERR_LOG
240 | r=$?
241 | if [ $r -ne 0 ]; then
242 | exit $r
243 | fi
244 | cd ..
245 | }
246 |
247 | function build_release() {
248 | cd nginx-$VERSION
249 | make clean >> $BUILD_LOG 2>>$ERR_LOG
250 | echo "Configuring release nginx-$VERSION" | tee -a $BUILD_LOG
251 | ./configure --prefix="$INSTALL_DIR/nginx-$VERSION" \
252 | $EMBEDDED_OPTS \
253 | --with-cc-opt="$ADDITIONAL_INCLUDES" \
254 | --with-ld-opt="$ADDITIONAL_LIBS" \
255 | --add-module=../ngx_devel_kit \
256 | --add-module=../lua-nginx-module \
257 | --add-module=../.. >> $BUILD_LOG 2>>$ERR_LOG
258 |
259 | r=$?
260 | if [ $r -ne 0 ]; then
261 | exit $r
262 | fi
263 |
264 | echo "Build release nginx-$VERSION" | tee -a $BUILD_LOG
265 | make -j 8 >> $BUILD_LOG 2>>$ERR_LOG
266 |
267 | r=$?
268 | if [ $r -ne 0 ]; then
269 | exit $r
270 | fi
271 | make install >> $BUILD_LOG 2>>$ERR_LOG
272 | cd ..
273 | }
274 |
275 | function gitclone() {
276 | LD_LIBRARY_PATH="" git clone $1 >> $BUILD_LOG 2> /tmp/err
277 | if [ $? -ne 0 ]; then
278 | cat /tmp/err
279 | exit 1
280 | fi
281 | }
282 |
283 | function gitcheckout() {
284 | git checkout $1 >> $BUILD_LOG 2> /tmp/err
285 | if [ $? -ne 0 ]; then
286 | cat /tmp/err
287 | exit 1
288 | fi
289 | }
290 |
291 | function download_module() {
292 | if [ $download -eq 1 ] || [ ! -e $3.tar.gz ]; then
293 | if [ $download_all -eq 1 ] || [ ! -e $3.tar.gz ]; then
294 | echo "Download $1/$2/$3.git from=$4" | tee -a $BUILD_LOG
295 | gitclone $1/$2/$3.git
296 | echo "$1/$2/$3.git" > $3.log
297 | echo >> $3.log
298 | cd $3
299 | gitcheckout $4
300 | echo $4" : "$(git log -1 --oneline | awk '{print $1}') >> ../$3.log
301 | echo >> ../$3.log
302 | git log -1 | grep -E "(^[Cc]ommit)|(^[Aa]uthor)|(^[Dd]ate)" >> ../$3.log
303 | cd ..
304 | tar zcf $3.tar.gz $3
305 | rm -rf $3
306 | else
307 | echo "Get $3" | tee -a $BUILD_LOG
308 | fi
309 | else
310 | echo "Get $3" | tee -a $BUILD_LOG
311 | fi
312 | }
313 |
314 | function download_dep() {
315 | if [ $download -eq 1 ] || [ ! -e $2-$3.tar.gz ]; then
316 | if [ $download_all -eq 1 ] || [ ! -e $2-$3.tar.gz ]; then
317 | echo "Download $2-$3.$4" | tee -a $BUILD_LOG
318 | LD_LIBRARY_PATH="" curl -s -L -o $2-$3.tar.gz $1/$2-$3.$4
319 | echo "$1/$2-$3.$4" > $2.log
320 | else
321 | echo "Get $2-$3.tar.gz" | tee -a $BUILD_LOG
322 | fi
323 | else
324 | echo "Get $2-$3.tar.gz" | tee -a $BUILD_LOG
325 | fi
326 | }
327 |
328 | function extract_downloads() {
329 | cd src
330 |
331 | for d in $(ls -1 *.tar.gz)
332 | do
333 | echo "Extracting $d" | tee -a $BUILD_LOG
334 | tar zxf $d -C $BUILD_DIR --keep-old-files 2>>$ERR_LOG
335 | done
336 |
337 | cd ..
338 | }
339 |
340 | function download() {
341 | mkdir -p $BUILD_DIR 2>>$ERR_LOG
342 | mkdir $BUILD_DIR/deps 2>>$ERR_LOG
343 |
344 | mkdir src 2>>$ERR_LOG
345 | mkdir src/lua_modules 2>>$ERR_LOG
346 |
347 | cd src
348 |
349 | download_dep http://nginx.org/download nginx $VERSION tar.gz
350 | download_dep http://mirror.linux-ia64.org/apache/zookeeper/zookeeper-3.5.8 apache-zookeeper $ZOO_VERSION tar.gz
351 | download_dep http://ftp.cs.stanford.edu/pub/exim/pcre pcre $PCRE_VERSION tar.gz
352 | download_dep http://zlib.net zlib $ZLIB_VERSION tar.gz
353 |
354 | download_module https://github.com simpl ngx_devel_kit master
355 | download_module https://github.com openresty lua-nginx-module v0.10.15
356 | download_module https://github.com openresty luajit2 v2.1-agentzh
357 | download_module https://github.com openresty lua-cjson master
358 |
359 | cd ..
360 | }
361 |
362 | function install_file() {
363 | echo "Install $1" | tee -a $BUILD_LOG
364 | if [ ! -e "$INSTALL_DIR/nginx-$VERSION/$2" ]; then
365 | mkdir -p "$INSTALL_DIR/nginx-$VERSION/$2"
366 | fi
367 | if [ "$4" == "" ]; then
368 | if [ "$3" == "" ]; then
369 | cp -r $1 "$INSTALL_DIR/nginx-$VERSION/$2/"
370 | else
371 | cp -r $1 "$INSTALL_DIR/nginx-$VERSION/$2/$3"
372 | fi
373 | else
374 | echo $4 > "$INSTALL_DIR/nginx-$VERSION/$2/$3"
375 | fi
376 | }
377 |
378 | function install_gzip() {
379 | echo "Install $1" | tee -a $BUILD_LOG
380 | if [ ! -e "$INSTALL_DIR/nginx-$VERSION/$2" ]; then
381 | mkdir -p "$INSTALL_DIR/nginx-$VERSION/$2"
382 | fi
383 | if [ "$4" == "" ]; then
384 | if [ "$3" == "" ]; then
385 | tar zxf $1 -C "$INSTALL_DIR/nginx-$VERSION/$2/"
386 | else
387 | tar zxf $1 -C "$INSTALL_DIR/nginx-$VERSION/$2/$3"
388 | fi
389 | else
390 | echo $4 > "$INSTALL_DIR/nginx-$VERSION/$2/$3"
391 | fi
392 | }
393 |
394 | function install_files() {
395 | for f in $(ls $1)
396 | do
397 | install_file $f $2
398 | done
399 | }
400 |
401 | function build() {
402 | cd $BUILD_DIR
403 |
404 | if [ $build_only -eq 0 ]; then
405 | patch -N -p0 < $DIR/patches/lua-cjson-Makefile.patch
406 | fi
407 |
408 | if [ $build_deps -eq 1 ] || [ ! -e deps/luajit ]; then
409 | build_luajit
410 | fi
411 | if [ $build_deps -eq 1 ] || [ ! -e deps/zookeeper ]; then
412 | build_zoo
413 | fi
414 | if [ $build_deps -eq 1 ] || [ ! -e deps/zlib ]; then
415 | build_zlib
416 | fi
417 | if [ $build_deps -eq 1 ] || [ ! -e deps/pcre ]; then
418 | build_pcre
419 | fi
420 |
421 | build_cJSON
422 |
423 | build_release
424 |
425 | install_file "$JIT_PREFIX/usr/local/lib/*.$shared*" lib
426 | install_file "lua-cjson/cjson.so" lib/lua/5.1
427 |
428 | install_files "$ZOO_PREFIX/lib/libzookeeper_mt.$shared*" lib
429 |
430 | install_files "$ZLIB_PREFIX/lib/libz.$shared*" lib
431 |
432 | install_files "$PCRE_PREFIX/lib/libpcre.$shared*" lib
433 | install_files "$PCRE_PREFIX/lib/libpcreposix.$shared*" lib
434 |
435 | chmod 755 $INSTALL_DIR/nginx-$VERSION/lib/*.$shared*
436 |
437 | cd $DIR
438 | }
439 |
440 | if [ $build_only -eq 0 ]; then
441 | clean
442 | fi
443 | download
444 | if [ $download_only -eq 0 ]; then
445 | if [ $build_only -eq 0 ]; then
446 | extract_downloads
447 | fi
448 | build
449 | fi
450 |
451 | function install_resty_module() {
452 | if [ $7 -eq 1 ] || [ ! -e $3.tar.gz ]; then
453 | if [ $8 -eq 1 ] || [ ! -e $3.tar.gz ]; then
454 | echo "Download $1/$2/$3.git from=$6" | tee -a $BUILD_LOG
455 | gitclone $1/$2/$3.git
456 | echo "$1/$2/$3.git" > $3.log
457 | echo >> $3.log
458 | cd $3
459 | gitcheckout $6
460 | echo $6" : "$(git log -1 --oneline | awk '{print $1}') >> ../$3.log
461 | echo >> ../$3.log
462 | git log -1 | grep -E "(^[Cc]ommit)|(^[Aa]uthor)|(^[Dd]ate)" >> ../$3.log
463 | cd ..
464 | tar zcf $3.tar.gz $3
465 | rm -rf $3
466 | else
467 | echo "Get $3-$6" | tee -a $BUILD_LOG
468 | fi
469 | else
470 | echo "Get $3-$6" | tee -a $BUILD_LOG
471 | fi
472 | if [ $9 -eq 0 ]; then
473 | echo "Install $3/$4" | tee -a $BUILD_LOG
474 | if [ ! -e "$INSTALL_DIR/nginx-$VERSION/$5" ]; then
475 | mkdir -p "$INSTALL_DIR/nginx-$VERSION/$5"
476 | fi
477 | if [ -e $3.tar.gz ]; then
478 | tar zxf $3.tar.gz
479 | cp -r $3/$4 "$INSTALL_DIR/nginx-$VERSION/$5/"
480 | rm -rf $3
481 | fi
482 | fi
483 | }
484 |
485 | uninstall_file() {
486 | rm -rf $INSTALL_DIR/nginx-$VERSION/$1
487 | }
488 |
489 | make_dir() {
490 | mkdir $INSTALL_DIR/nginx-$VERSION/$1
491 | }
492 |
493 | function install_lua_modules() {
494 | cd $DIR
495 |
496 | install_file conf .
497 | install_file html .
498 | install_file lua .
499 |
500 | install_file scripts/start.sh .
501 | install_file scripts/stop.sh .
502 | install_file scripts/restart.sh .
503 | }
504 |
505 | install_lua_modules
506 |
507 | cp LICENSE "$INSTALL_PREFIX/nginx-$VERSION$SUFFIX/LICENSE"
508 |
509 | cd "$DIR"
510 |
511 | kernel_name=$(uname -s)
512 | kernel_version=$(uname -r)
513 |
514 | cd install
515 |
516 | tar zcvf nginx-$VERSION$SUFFIX-$kernel_name-$kernel_version.tar.gz nginx-$VERSION$SUFFIX
517 | rm -rf nginx-$VERSION$SUFFIX
518 |
519 | cd ..
520 |
521 | exit $r
522 |
--------------------------------------------------------------------------------
/conf/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes 1;
2 |
3 | pid logs/nginx.pid;
4 |
5 | error_log logs/error.log info;
6 | error_log logs/debug.log debug;
7 |
8 | events {
9 | worker_connections 1024;
10 | multi_accept on;
11 | }
12 |
13 | include "zoo.conf";
--------------------------------------------------------------------------------
/conf/zoo.conf:
--------------------------------------------------------------------------------
1 | http {
2 | lua_load_resty_core off;
3 |
4 | zookeeper 127.0.0.1:2181;
5 | zookeeper_log_level debug;
6 | zookeeper_recv_timeout 60000;
7 | zookeeper_ethemeral_node /nginx 127.0.0.1 "nginx";
8 |
9 | zookeeper_node /nginx/persistent PERSISTENT "persistent";
10 |
11 | lua_shared_dict config 64k;
12 | lua_shared_dict zoo_cache 10m;
13 |
14 | # path to LUA modules
15 | lua_package_path "lib/?.lua;;lua/?.lua;;";
16 | lua_package_cpath "lib/lua/5.1/?.so;;";
17 |
18 | lua_socket_log_errors off;
19 |
20 | include mime.types;
21 |
22 | client_body_buffer_size 32m;
23 | client_max_body_size 32m;
24 |
25 | init_by_lua_block {
26 | ngx.shared.config:set("zoo.cache.on", true)
27 | ngx.shared.config:set("zoo.cache.ttl", 60)
28 | ngx.shared.config:set("zoo.debug", true)
29 |
30 | local cjson = require "cjson"
31 |
32 | ngx.shared.config:set("zoo.cache.path.ttl", cjson.encode({
33 | { path = "/nginx", ttl = 0 },
34 | { path = "/services", ttl = 0 }
35 | }))
36 | }
37 |
38 | init_worker_by_lua_block {
39 | assert(ngx.timer.at(1, function()
40 | local zoo = require "zoo"
41 | local cjson = require "cjson"
42 |
43 | zoo.delete_recursive("/watched1")
44 | zoo.delete_recursive("/watched2")
45 |
46 | zoo.create("/watched1")
47 | zoo.create("/watched2")
48 |
49 | local function on_event(ctx)
50 | local data = assert(zoo.watch(ctx.path, ctx.watcher_type, on_event, ctx))
51 | ngx.log(ngx.INFO, "on_event: ", ctx.path, "=", cjson.encode(data))
52 | end
53 |
54 | on_event {
55 | watcher_type = zoo.WatcherType.DATA,
56 | path = "/watched1"
57 | }
58 |
59 | on_event {
60 | watcher_type = zoo.WatcherType.DATA,
61 | path = "/watched2"
62 | }
63 |
64 | on_event {
65 | watcher_type = zoo.WatcherType.CHILDREN,
66 | path = "/watched1"
67 | }
68 |
69 | on_event {
70 | watcher_type = zoo.WatcherType.CHILDREN,
71 | path = "/watched2"
72 | }
73 |
74 | local stop
75 |
76 | assert(ngx.timer.at(60, function()
77 | assert(zoo.unwatch("/watched1", zoo.WatcherType.DATA))
78 | assert(zoo.unwatch("/watched1", zoo.WatcherType.CHILDREN))
79 | assert(zoo.unwatch("/watched2", zoo.WatcherType.DATA))
80 | assert(zoo.unwatch("/watched2", zoo.WatcherType.CHILDREN))
81 | ngx.log(ngx.INFO, "unwatch")
82 | stop = ngx.now() + 10
83 | end))
84 |
85 | local i = 0
86 |
87 | local function change(premature)
88 | if premature or (stop and stop < ngx.now()) then
89 | return
90 | end
91 |
92 | pcall(function()
93 | if zoo.connected() then
94 | i = i + 1
95 |
96 | assert(zoo.set("/watched1", i))
97 | assert(zoo.set("/watched2", i))
98 |
99 | if i % 2 == 1 then
100 | assert(zoo.create("/watched1/1"))
101 | assert(zoo.create("/watched2/1"))
102 | else
103 | assert(zoo.delete("/watched1/1"))
104 | assert(zoo.delete("/watched2/1"))
105 | end
106 |
107 | ngx.log(ngx.INFO, "update")
108 | end
109 | end)
110 |
111 | assert(ngx.timer.at(1, change))
112 | end
113 |
114 | assert(ngx.timer.at(1, change))
115 | end))
116 | }
117 |
118 | server {
119 | listen 12181;
120 |
121 | default_type application/json;
122 |
123 | server_name zoo;
124 |
125 | include zoo_server.conf;
126 | }
127 |
128 | server {
129 | listen 8001;
130 | zookeeper_register_port /nginx/8001 8001 "nginx-8001";
131 | location / {
132 | return 200 '8001';
133 | }
134 | }
135 |
136 | server {
137 | listen 8002;
138 | location /a {
139 | zookeeper_register_port /nginx/8002/a 8002;
140 | return 200 '8002';
141 | }
142 | location /b {
143 | zookeeper_ethemeral_node /nginx/8002/b 127.0.0.1:8002;
144 | return 200 '8002';
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/conf/zoo_server.conf:
--------------------------------------------------------------------------------
1 | location / {
2 | root html/zoo;
3 | index index.html;
4 | }
5 |
6 | location = /zoo/get {
7 | content_by_lua_block {
8 | local api = require "zoo.api"
9 | local cjson = require "cjson"
10 | ngx.say(cjson.encode(api.get(ngx.var.arg_znode)))
11 | }
12 | }
13 |
14 | location = /zoo/childrens {
15 | content_by_lua_block {
16 | local api = require "zoo.api"
17 | local cjson = require "cjson"
18 | ngx.say(cjson.encode(api.childrens(ngx.var.arg_znode)))
19 | }
20 | }
21 |
22 | location = /zoo/set {
23 | content_by_lua_block {
24 | local api = require "zoo.api"
25 | local cjson = require "cjson"
26 | ngx.say(cjson.encode(api.set(ngx.var.arg_znode, ngx.var.arg_value, ngx.var.arg_version)))
27 | }
28 | }
29 |
30 | location = /zoo/create {
31 | content_by_lua_block {
32 | local api = require "zoo.api"
33 | local cjson = require "cjson"
34 | ngx.say(cjson.encode(api.create(ngx.var.arg_znode, ngx.var.arg_value)))
35 | }
36 | }
37 |
38 | location = /zoo/delete {
39 | content_by_lua_block {
40 | local api = require "zoo.api"
41 | local cjson = require "cjson"
42 | ngx.say(cjson.encode(api.delete(ngx.var.arg_znode, ngx.var.arg_recursive)))
43 | }
44 | }
45 |
46 | location = /zoo/tree {
47 | content_by_lua_block {
48 | local api = require "zoo.api"
49 | local cjson = require "cjson"
50 | ngx.say(cjson.encode(api.tree(ngx.var.arg_znode,
51 | ngx.var.arg_stat and ngx.var.arg_stat:match("[1yY]"))))
52 | }
53 | }
54 |
55 | location = /zoo/tree2 {
56 | content_by_lua_block {
57 | local zoo = require "zoo"
58 | local cjson = require "cjson"
59 | local resp, err = zoo.tree(ngx.var.arg_znode,
60 | ngx.var.arg_stat and ngx.var.arg_stat:match("[1yY]"))
61 | ngx.say(resp and cjson.encode(resp) or err)
62 | }
63 | }
64 |
65 | location = /zoo/import {
66 | content_by_lua_block {
67 | local api = require "zoo.api"
68 |
69 | local method = ngx.req.get_method()
70 | if method ~= "POST" and method ~= "PUT" then
71 | ngx.exit(ngx.HTTP_BAD_REQUEST)
72 | end
73 |
74 | local content_type = ngx.req.get_headers().content_type
75 |
76 | if not content_type or content_type:lower() ~= "application/json" then
77 | ngx.exit(ngx.HTTP_BAD_REQUEST)
78 | end
79 |
80 | ngx.req.read_body()
81 | local data = ngx.req.get_body_data()
82 |
83 | local ok, err = api.import(ngx.var.arg_znode or "/", data)
84 | if ok then
85 | ngx.say("Imported")
86 | else
87 | ngx.say(err)
88 | end
89 | }
90 | }
--------------------------------------------------------------------------------
/config:
--------------------------------------------------------------------------------
1 | ngx_addon_name=ngx_zookeeper_lua_module
2 | HTTP_ZOOKEEPER_LUA_SRCS="$ngx_addon_dir/ngx_zookeeper_lua_module.c"
3 |
4 | ZOO_REQUIRED_INCS="$ZOO_PREFIX/include"
5 | ZOO_REQUIRED_LIBS="-L$ZOO_PREFIX/lib -lzookeeper_mt"
6 |
7 | CORE_INCS="$CORE_INCS $ngx_addon_dir"
8 |
9 | if test -n "$ngx_module_link"; then
10 | ngx_module_type=HTTP
11 | ngx_module_name=$ngx_addon_name
12 | ngx_module_srcs="$HTTP_ZOOKEEPER_LUA_SRCS"
13 | ngx_module_incs="$ZOO_REQUIRED_INCS"
14 | ngx_module_libs="$ZOO_REQUIRED_LIBS"
15 |
16 | . auto/module
17 | else
18 | HTTP_MODULES="$HTTP_MODULES $ngx_addon_name"
19 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $HTTP_ZOOKEEPER_LUA_SRCS"
20 |
21 | CORE_INCS="$CORE_INCS $ZOO_REQUIRED_INCS"
22 | CORE_LIBS="$CORE_LIBS $ZOO_REQUIRED_LIBS"
23 | fi
24 |
--------------------------------------------------------------------------------
/html/zoo/css/index.css:
--------------------------------------------------------------------------------
1 | #page {min-height:600px;}
2 | .package {padding:3px;border-radius:3px;margin-top:3px;}
3 | .header {cursor:pointer;}
4 |
5 | .name {color:gray;}
6 |
7 | .array {margin-left:12px;background-color:#FFD8BB;border:thin solid #FFB780;}
8 | .object {margin-left:12px;background-color:#E7F1FE;border:thin solid #7DA2CE;font-weight: bold;}
9 | .string {color:red;margin-left:28px;padding:3px;font-weight: normal;font-style: italic;}
10 | .number {color:blue;margin-left:28;padding:3px;font-weight: normal;font-style: italic;}
11 | .function {color:green;margin-left:28px;padding:3px;font-weight: normal;font-style: normal;}
12 |
13 | .open .children {display:block;}
14 | .closed .children {display:none;}
15 |
16 | .arrow {background-image:url("/img/d.png"); background-repeat:no-repeat; background-color:transparent; height:15px; width:15px; display:inline-block;}
17 |
18 | .open .arrow {background-position:-20px 0;}
19 | .closed .arrow {background-position:0 0;}
20 |
21 | .type {color:gray;font-size:8pt;float:right;}
22 |
23 | .hide {display:none;}
24 |
25 | #main {width:100%;height:500px;overflow-y:scroll;}
--------------------------------------------------------------------------------
/html/zoo/css/layout.css:
--------------------------------------------------------------------------------
1 |
2 | html {
3 | background-color: #ebf0fa;
4 | background-image: -moz-linear-gradient(center top , #5e8ec6, #E4E4E4);
5 | margin-top:50px;
6 | }
7 |
8 | body {
9 | background-color: transparent;
10 | font-family: "Helvetica Neue",Arial,sans-serif;
11 | font-size: 11pt;
12 | padding: 1px 0 30px;
13 | }
14 |
15 | #page {
16 | background-color: #FFFFFF;
17 | border-radius: 5px 5px 5px 5px;
18 | box-shadow: 0 0 10px #000000;
19 | clear: left;
20 | padding: 10px 0 0;
21 | margin-top:50px;
22 | }
23 |
24 | #header, #page, #footer {
25 | margin: 0 auto;
26 | position: relative;
27 | width: 830px;
28 | }
29 |
30 | #header {
31 | margin-top:15px;
32 | z-index:100;
33 | }
34 |
35 | #logo-header{
36 | margin-top:5px;
37 | }
38 |
39 | a {
40 | background: none repeat scroll 0 0 transparent;
41 | border: 0 none;
42 | font-size: 100%;
43 | margin: 0;
44 | padding: 0;
45 | vertical-align: baseline;
46 | }
47 |
48 | #site-nav, #site-nav ul {
49 | float: right;
50 | }
51 | #site-nav {
52 | font-family: Helvetica,Arial,sans-serif;
53 | font-size: 1.4em;
54 | font-weight: bold;
55 | }
56 | .nav ul {
57 | list-style: none outside none;
58 | }
59 |
60 | #site-nav li.alpha, #site-nav li.alpha a {
61 | border-radius: 4px 0 0 4px;
62 | }
63 |
64 | #site-nav li {
65 | background-color: #8BD92F;
66 | background-image: -moz-linear-gradient(center top , #f4cecf, #fb9ca0);
67 | float: left;
68 | }
69 |
70 | #site-nav li.alpha, #site-nav li.alpha a {
71 | border-radius: 4px 0 0 4px;
72 | }
73 |
74 | #site-nav li.omega, #site-nav li.omega a {
75 | border-radius: 0 4px 4px 0;
76 | }
77 |
78 | #site-nav {
79 | font-family: Helvetica,Arial,sans-serif;
80 | font-size: 1.4em;
81 | font-weight: bold;
82 | }
83 |
84 | #site-nav a {
85 | border-left: 1px solid rgba(255, 255, 255, 0.3);
86 | border-right: 1px solid rgba(0, 0, 0, 0.1);
87 | color: #FFFFFF;
88 | display: block;
89 | float: left;
90 | height: 34px;
91 | line-height: 34px;
92 | padding: 0 13px;
93 | text-decoration: none;
94 | text-shadow: 0 -1px 0 #456B22;
95 | }
96 |
97 | #site-nav a:hover {
98 | background: none repeat scroll 0 0 rgba(0, 0, 0, 0.1);
99 | }
100 |
101 | #page .divider {
102 | border-top: 1px dotted #AAAAAA;
103 | margin-top: 25px;
104 | padding-top: 30px;
105 | }
106 |
107 | #page article {
108 | margin: 0 20px;
109 | padding: 20px 0 20px;
110 | }
111 |
112 | #page article h3 {
113 | color: #000000;
114 | font-size: 15pt;
115 | font-weight: bold;
116 | margin: 15px 0 10px;
117 | }
118 |
119 | #page #page-header h2, #page #page-header p {
120 | width: 500px;
121 | }
122 |
123 | #page #page-header h1 {
124 | color:#807f7f;
125 | font-size: 20pt;
126 | font-weight: bold;
127 | line-height: 1.3em;
128 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;";
129 | }
130 |
131 | #page #page-header h3 {
132 | font-size: 10pt;
133 | font-weight: bold;
134 | }
135 |
136 | #page #page-header {
137 | background-color: #FFFFFF;
138 | background-image: -moz-linear-gradient(center top , #FFFFFF, #E4E4E4);
139 | border-bottom: 5px solid #298f00;
140 | position: relative;
141 | text-shadow: 0 1px 0 #FFFFFF;
142 | }
143 |
144 | blue {color:#688dad;font-weight:bold;}
145 | red {color:red;font-weight:bold;}
146 |
147 | #releaseNotes {
148 | list-style:none;
149 | }
150 |
151 | .inner-content {
152 | padding: 30px 30px 10px;
153 | }
154 |
155 | #page p {
156 | color: #4D4D4D;
157 | line-height: 1.5em;
158 | margin: 0 0 10px;
159 | }
160 |
161 | .hide {display:none;}
--------------------------------------------------------------------------------
/html/zoo/img/d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZigzagAK/ngx_zookeeper_lua/363970de7c074b89a89781c9d42dfabc9a06da98/html/zoo/img/d.png
--------------------------------------------------------------------------------
/html/zoo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Zookeeper
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/html/zoo/js/index.js:
--------------------------------------------------------------------------------
1 |
2 | var transforms = {
3 | 'object':{'tag':'div','class':'package ${show} ${type}','children':[
4 | {'tag':'div','class':'header','children':[
5 | {'tag':'div','class':function(obj){
6 |
7 | var classes = ["arrow"];
8 |
9 | if( getValue(obj.value) !== undefined ) classes.push("hide");
10 |
11 | return(classes.join(' '));
12 | }},
13 | {'tag':'span','class':'name','html':function(obj) {
14 | if ( obj.name === 'value' && getValue(obj.value) === "''" ) return '';
15 | return obj.name;
16 | }},
17 | {'tag':'span','class':'value','html':function(obj) {
18 | var value = getValue(obj.value);
19 | if( value !== undefined && value !== "''" ) return(" : " + value);
20 | else return('');
21 | }},
22 | {'tag':'span','class':'type','html':''}
23 | ]},
24 | {'tag':'div','class':'children','children':function(obj){return(children(obj.value));}}
25 | ]}
26 | };
27 |
28 | $(function(){
29 |
30 | $.get( "/zoo/tree2?znode=/&stat=0" ).done(function(data) { visualize(data); })
31 |
32 | });
33 |
34 | function visualize(json) {
35 |
36 | $('#top').html('');
37 |
38 | $('#top').json2html(convert('/',json,'open'),transforms.object);
39 |
40 | regEvents();
41 | }
42 |
43 | function getValue(obj) {
44 | var type = $.type(obj);
45 |
46 | //Determine if this object has children
47 | switch(type) {
48 | case 'array':
49 | case 'object':
50 | return(undefined);
51 | break;
52 |
53 | case 'function':
54 | //none
55 | return('function');
56 | break;
57 |
58 | case 'string':
59 | return("'" + obj.replace('\0','') + "'");
60 | break;
61 |
62 | default:
63 | return(obj);
64 | break;
65 | }
66 | }
67 |
68 | //Transform the children
69 | function children(obj){
70 | var type = $.type(obj);
71 |
72 | //Determine if this object has children
73 | switch(type) {
74 | case 'array':
75 | case 'object':
76 | return(json2html.transform(obj,transforms.object));
77 | break;
78 |
79 | default:
80 | //This must be a litteral
81 | break;
82 | }
83 | }
84 |
85 | function convert(name,obj,show) {
86 |
87 | var type = $.type(obj);
88 |
89 | if(show === undefined) show = 'closed';
90 |
91 | var children = [];
92 |
93 | //Determine the type of this object
94 | switch(type) {
95 | case 'array':
96 | //Transform array
97 | //Itterrate through the array and add it to the elements array
98 | var len=obj.length;
99 | for(var j=0;j 2 )
171 | if(key.substring(0,2).toLowerCase() == 'on') {
172 |
173 | //Determine if we should add events
174 | if(options.events) {
175 |
176 | //if so then setup the event data
177 | var data = {
178 | 'action':transform[key],
179 | 'obj':obj,
180 | 'data':options.eventData,
181 | 'index':index
182 | };
183 |
184 | //create a new id for this event
185 | var id = json2html._guid();
186 |
187 | //append the new event to this elements events
188 | element.events[element.events.length] = {'id':id,'type':key.substring(2),'data':data};
189 |
190 | //Insert temporary event property (json2html-event-id) into the element
191 | element.html += " json2html-event-id-"+key.substring(2)+"='" + id + "'";
192 | }
193 | //this is an event
194 | isEvent = true;
195 | }
196 |
197 | //If this wasn't an event AND we actually have a value then add it as a property
198 | if( !isEvent){
199 | //Get the value
200 | var val = json2html._getValue(obj, transform, key, index);
201 |
202 | //Make sure we have a value
203 | if(val !== undefined) {
204 | var out;
205 |
206 | //Determine the output type of this value (wrap with quotes)
207 | if(typeof val === 'string') out = '"' + val.replace(/"/g, '"') + '"';
208 | else out = val;
209 |
210 | //creat the name value pair
211 | element.html += ' ' + key + '=' + out;
212 | }
213 | }
214 | break;
215 | }
216 | }
217 |
218 | //close the opening tag
219 | element.html += '>';
220 |
221 | //add the innerHTML (if we have any)
222 | if(html) element.html += html;
223 |
224 | //add the children (if we have any)
225 | element = json2html._append(element,children);
226 |
227 | //add the closing tag
228 | element.html += '' + tag + '>';
229 | }
230 | }
231 |
232 | //Return the output object
233 | return(element);
234 | },
235 |
236 | //Get a new GUID (used by events)
237 | '_guid':function() {
238 | var S4 = function() {
239 | return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
240 | };
241 | return (S4()+S4()+"-"+S4()+S4()+"-"+S4()+S4());
242 | },
243 |
244 | //Get the html value of the object
245 | '_getValue':function(obj, transform, key,index) {
246 |
247 | var out = '';
248 |
249 | var val = transform[key];
250 | var type = typeof val;
251 |
252 | if (type === 'function') {
253 | return(val.call(obj,obj,index));
254 | } else if (type === 'string') {
255 | var _tokenizer = new json2html._tokenizer([
256 | /\$\{([^\}\{]+)\}/
257 | ],function( src, real, re ){
258 | return real ? src.replace(re,function(all,name){
259 |
260 | //Split the string into it's seperate components
261 | var components = name.split('.');
262 |
263 | //Set the object we use to query for this name to be the original object
264 | var useObj = obj;
265 |
266 | //Output value
267 | var outVal = '';
268 |
269 | //Parse the object components
270 | var c_len = components.length;
271 | for (var i=0;i 0 ) {
274 |
275 | var newObj = useObj[components[i]];
276 | useObj = newObj;
277 | if(useObj === null || useObj === undefined) break;
278 | }
279 | }
280 |
281 | //As long as we have an object to use then set the out
282 | if(useObj !== null && useObj !== undefined) outVal = useObj;
283 |
284 | return(outVal);
285 | }) : src;
286 | });
287 |
288 | out = _tokenizer.parse(val).join('');
289 | } else {
290 | out = val;
291 | }
292 |
293 | return(out);
294 | },
295 |
296 | //Tokenizer
297 | '_tokenizer':function( tokenizers, doBuild ){
298 |
299 | if( !(this instanceof json2html._tokenizer ) )
300 | return new json2html._tokenizer( tokenizers, doBuild );
301 |
302 | this.tokenizers = tokenizers.splice ? tokenizers : [tokenizers];
303 | if( doBuild )
304 | this.doBuild = doBuild;
305 |
306 | this.parse = function( src ){
307 | this.src = src;
308 | this.ended = false;
309 | this.tokens = [ ];
310 | do {
311 | this.next();
312 | } while( !this.ended );
313 | return this.tokens;
314 | };
315 |
316 | this.build = function( src, real ){
317 | if( src )
318 | this.tokens.push(
319 | !this.doBuild ? src :
320 | this.doBuild(src,real,this.tkn)
321 | );
322 | };
323 |
324 | this.next = function(){
325 | var self = this,
326 | plain;
327 |
328 | self.findMin();
329 | plain = self.src.slice(0, self.min);
330 |
331 | self.build( plain, false );
332 |
333 | self.src = self.src.slice(self.min).replace(self.tkn,function( all ){
334 | self.build(all, true);
335 | return '';
336 | });
337 |
338 | if( !self.src )
339 | self.ended = true;
340 | };
341 |
342 | this.findMin = function(){
343 | var self = this, i=0, tkn, idx;
344 | self.min = -1;
345 | self.tkn = '';
346 |
347 | while(( tkn = self.tokenizers[i++]) !== undefined ){
348 | idx = self.src[tkn.test?'search':'indexOf'](tkn);
349 | if( idx != -1 && (self.min == -1 || idx < self.min )){
350 | self.tkn = tkn;
351 | self.min = idx;
352 | }
353 | }
354 | if( self.min == -1 )
355 | self.min = self.src.length;
356 | };
357 | }
358 | };
359 |
--------------------------------------------------------------------------------
/lua/zoo.lua:
--------------------------------------------------------------------------------
1 | local zoo = require "ngx.zookeeper"
2 | local cjson = require "cjson"
3 |
4 | local ffi = require 'ffi'
5 |
6 | local C = ffi.C
7 |
8 | ffi.cdef[[
9 | int usleep(unsigned int usec);
10 | ]]
11 |
12 | local function blocking_sleep(sec)
13 | return C.usleep(sec * 1000000)
14 | end
15 |
16 | local timeout = zoo.timeout()
17 | local operation_timeout
18 |
19 | local _M = {
20 | _VERSION = "2.7.2",
21 |
22 | errors = {
23 | ZOO_OK = "OK",
24 | ZOO_SYSTEMERROR = "System error",
25 | ZOO_RUNTIMEINCONSISTENCY = "Runtime inconsistency",
26 | ZOO_DATAINCONSISTENCY = "Data inconsistency",
27 | ZOO_CONNECTIONLOSS = "Connection to the server has been lost",
28 | ZOO_MARSHALLINGERROR = "Error while marshalling or unmarshalling data",
29 | ZOO_UNIMPLEMENTED = "Operation not implemented",
30 | ZOO_TIMEOUT = "Operation timeout",
31 | ZOO_BADARGUMENTS = "Invalid argument",
32 | ZOO_INVALIDSTATE = "Invalid zhandle state",
33 | ZOO_APIERROR = "API error",
34 | ZOO_NONODE = "Znode does not exist",
35 | ZOO_NOAUTH = "Not authenticated",
36 | ZOO_BADVERSION = "Version conflict",
37 | ZOO_NOCHILDRENFOREPHEMERALS = "Ephemeral nodes may not have children",
38 | ZOO_NODEEXISTS = "Znode already exists",
39 | ZOO_NOTEMPTY = "The znode has children",
40 | ZOO_SESSIONEXPIRED = "The session has been expired by the server",
41 | ZOO_INVALIDCALLBACK = "Invalid callback specified",
42 | ZOO_INVALIDACL = "Invalid ACL specified",
43 | ZOO_AUTHFAILED = "Client authentication failed",
44 | ZOO_CLOSING = "ZooKeeper session is closing",
45 | ZOO_NOTHING = "No response from server",
46 | ZOO_SESSIONMOVED = "Session moved to a different server"
47 | },
48 |
49 | WatcherType = {
50 | CHILDREN = 4,
51 | DATA = 3
52 | },
53 |
54 | flags = {
55 | ZOO_PERSISTENT = 0,
56 | ZOO_EPHEMERAL = 1,
57 | ZOO_SEQUENCE = bit.lshift(1, 1),
58 | ZOO_PERSISTENT_SEQUENTIAL = 2;
59 | ZOO_EPHEMERAL_SEQUENTIAL = 3,
60 | ZOO_CONTAINER = 4,
61 | ZOO_PERSISTENT_WITH_TTL = 5,
62 | ZOO_PERSISTENT_SEQUENTIAL_WITH_TTL = 6
63 | }
64 | }
65 |
66 | local errors
67 | local WatcherType
68 | local set
69 | local create
70 | local delete
71 | local delete_recursive
72 | local childrens
73 | local watch
74 | local unwatch
75 | local clear_in_cache
76 |
77 | local CACHE = ngx.shared.zoo_cache
78 | local CONFIG = ngx.shared.config
79 |
80 | local pcall, xpcall = pcall, xpcall
81 | local ipairs, pairs = ipairs, pairs
82 | local assert = assert
83 | local unpack = unpack
84 | local type = type
85 | local now, update_time = ngx.now, ngx.update_time
86 | local ngx_log = ngx.log
87 | local sleep = ngx.sleep
88 | local WARN, DEBUG = ngx.WARN, ngx.DEBUG
89 | local sub = string.sub
90 | local rep = string.rep
91 | local tconcat, tinsert = table.concat, table.insert
92 | local md5, format = ngx.md5, string.format
93 |
94 | local json_decode = cjson.decode
95 | local json_encode = cjson.encode
96 |
97 | local zoo_cache_on = CONFIG:get("zoo.cache.on")
98 | local zoo_cache_ttl = CONFIG:get("zoo.cache.ttl") or 60
99 | local zoo_cache_path_ttl = json_decode(CONFIG:get("zoo.cache.path.ttl") or "{}")
100 | local zoo_decode_json = CONFIG:get("zoo.decode_json")
101 | local zoo_watch_interval = CONFIG:get("zoo.watch.interval") or 1
102 | local zoo_debug = CONFIG:get("zoo.debug")
103 |
104 | local function debug(fun)
105 | if zoo_debug then
106 | ngx_log(DEBUG, fun())
107 | end
108 | end
109 |
110 | table.sort(zoo_cache_path_ttl, function(l, r) return #l.path > #r.path end)
111 |
112 | local function json_pretty_encode(dt, lf, id, ac)
113 | local s, e = json_encode(dt)
114 | if not s then return s, e end
115 | lf, id, ac = lf or "\n", id or " ", ac or " "
116 | local i, j, k, n, r, p, q = 1, 0, 0, #s, {}, nil, nil
117 | local al = sub(ac, -1) == "\n"
118 | for x = 1, n do
119 | local c = sub(s, x, x)
120 | if not q and (c == "{" or c == "[") then
121 | r[i] = p == ":" and tconcat{ c, lf } or tconcat{ rep(id, j), c, lf }
122 | j = j + 1
123 | elseif not q and (c == "}" or c == "]") then
124 | j = j - 1
125 | if p == "{" or p == "[" then
126 | i = i - 1
127 | r[i] = tconcat{ rep(id, j), p, c }
128 | else
129 | r[i] = tconcat{ lf, rep(id, j), c }
130 | end
131 | elseif not q and c == "," then
132 | r[i] = tconcat{ c, lf }
133 | k = -1
134 | elseif not q and c == ":" then
135 | r[i] = tconcat{ c, ac }
136 | if al then
137 | i = i + 1
138 | r[i] = rep(id, j)
139 | end
140 | else
141 | if c == '"' and p ~= "\\" then
142 | q = not q and true or nil
143 | end
144 | if j ~= k then
145 | r[i] = rep(id, j)
146 | i, k = i + 1, j
147 | end
148 | r[i] = c
149 | end
150 | p, i = c, i + 1
151 | end
152 | return tconcat(r)
153 | end
154 |
155 | local get_ttl
156 | get_ttl = function(znode)
157 | zoo_cache_ttl = CONFIG:get("zoo.cache.ttl") or 60
158 | zoo_cache_path_ttl = json_decode(CONFIG:get("zoo.cache.path.ttl") or "{}")
159 | table.sort(zoo_cache_path_ttl, function(l, r) return #l.path > #r.path end)
160 | debug(function()
161 | return "zoo.cache.ttl=", zoo_cache_ttl, "; zoo.cache.path.ttl: ", json_encode(zoo_cache_path_ttl)
162 | end)
163 | get_ttl = function (znode)
164 | for _, z in ipairs(zoo_cache_path_ttl)
165 | do
166 | if z.path == znode:sub(1, #z.path) or znode:match(z.path) then
167 | return z.ttl
168 | end
169 | end
170 | return zoo_cache_ttl
171 | end
172 | return get_ttl(znode)
173 | end
174 |
175 | local function get_expires(op_timeout)
176 | update_time()
177 | return now() * 1000 + (op_timeout or timeout)
178 | end
179 |
180 | local function suspend(sec)
181 | if not pcall(sleep, sec) then
182 | if ngx.get_phase() ~= "init_worker" then
183 | ngx_log(WARN, "blocking sleep function is used")
184 | end
185 | blocking_sleep(sec)
186 | end
187 | end
188 |
189 | local function zoo_call(fun)
190 | local sc, err = fun()
191 | if not sc then
192 | return nil, err
193 | end
194 |
195 | local expires = get_expires(operation_timeout)
196 | local completed, value, stat
197 |
198 | operation_timeout = nil
199 |
200 | repeat
201 | suspend(0.001)
202 | if not xpcall(function()
203 | completed, value, err, stat = zoo.check_completition(sc)
204 | return true
205 | end, function(e)
206 | err = e
207 | return e
208 | end) then
209 | return nil, err
210 | end
211 | until completed or now() * 1000 > expires
212 |
213 | if completed then
214 | return not err and { value, stat } or nil, err
215 | end
216 |
217 | return nil, errors.ZOO_TIMEOUT
218 | end
219 |
220 | function _M.set_operation_timeout(op_timeout)
221 | operation_timeout = op_timeout
222 | end
223 |
224 | function _M.clear_in_cache(znode)
225 | CACHE:delete("$c:" .. znode)
226 | CACHE:delete("$v:" .. znode)
227 | end
228 |
229 | function _M.clear_cache(prefix)
230 | if not prefix then
231 | CACHE:flush_all()
232 | else
233 | prefix = "^%$[cv]:" .. prefix
234 | for _,key in ipairs(CACHE:get_keys(0) or {}) do
235 | if key:match(prefix) then
236 | CACHE:delete(key)
237 | end
238 | end
239 | end
240 | CACHE:flush_expired()
241 | end
242 |
243 | local function save_in_cache(prefix, znode, v, stat)
244 | if not zoo_cache_on then
245 | return
246 | end
247 |
248 | local ttl = get_ttl(znode)
249 | if ttl == 0 then
250 | return
251 | end
252 |
253 | local cached = json_encode { stat = stat, value = v }
254 |
255 | local ok, err = CACHE:set(prefix .. ":" .. znode, cached, zoo_cache_ttl)
256 |
257 | if ok then
258 | debug(function()
259 | return "zoo set cached: ttl=", ttl, "s,", znode, "=", cached
260 | end)
261 | else
262 | ngx_log(WARN, "zoo set cached: ", err)
263 | end
264 | end
265 |
266 | local function get_from_cache(prefix, znode)
267 | if zoo_cache_on then
268 | local cached = CACHE:get(prefix .. ":" .. znode)
269 | if cached then
270 | debug(function()
271 | return "zoo get cached: ", znode, "=", cached
272 | end)
273 | return json_decode(cached)
274 | end
275 | end
276 | end
277 |
278 | function _M.get(znode, nocache)
279 | if not nocache then
280 | local cached = get_from_cache("$v", znode)
281 | if cached then
282 | return cached.value, cached.stat
283 | end
284 | end
285 |
286 | local data, err = zoo_call(function()
287 | return zoo.aget(znode)
288 | end)
289 |
290 | if not data then
291 | return nil, nil, err
292 | end
293 |
294 | local value, stat = unpack(data)
295 |
296 | debug(function()
297 | return "zoo get: ", znode, "=", value
298 | end)
299 |
300 | if zoo_decode_json and value and value:match("^%s*{") then
301 | -- may be json
302 | local ok, object = pcall(json_decode, value)
303 | if ok then
304 | -- value is valid object
305 | value = object
306 | end
307 | end
308 |
309 | save_in_cache("$v", znode, value or "", stat)
310 |
311 | return value or "", stat
312 | end
313 |
314 | function _M.childrens(znode, nocache)
315 | if not nocache then
316 | local cached = get_from_cache("$c", znode)
317 | if cached then
318 | return cached.value or {}
319 | end
320 | end
321 |
322 | local data, err = zoo_call(function()
323 | return zoo.achildrens(znode)
324 | end)
325 |
326 | if not data then
327 | return nil, err
328 | end
329 |
330 | local childs, stat = unpack(data)
331 |
332 | save_in_cache("$c", znode, childs, nil)
333 | debug(function()
334 | return "zoo childrens: ", znode, "=", json_encode(childs)
335 | end)
336 |
337 | return childs or {}
338 | end
339 |
340 | function _M.set(znode, value, version)
341 | value = type(value) == "table" and (
342 | #value == 0 and json_pretty_encode(value) or tconcat(value, "\n")
343 | ) or value or ""
344 |
345 | local data, err = zoo_call(function()
346 | return zoo.aset(znode, value, version or -1)
347 | end)
348 |
349 | clear_in_cache(znode)
350 |
351 | return data and data[2] or nil, err
352 | end
353 |
354 | function _M.create(znode, value, flags)
355 | value = type(value) == "table" and (
356 | #value == 0 and json_pretty_encode(value) or tconcat(value, "\n")
357 | ) or value or ""
358 |
359 | local data, err = zoo_call(function()
360 | return zoo.acreate(znode, value, flags or 0)
361 | end)
362 |
363 | return data and (data[1] or "") or nil, err
364 | end
365 |
366 | function _M.create_path(znode, val, flags)
367 | local path = "/"
368 |
369 | local data, err = zoo_call(function()
370 | return zoo.aget(znode)
371 | end)
372 |
373 | if data then
374 | if val and data ~= val then
375 | return set(znode, val)
376 | end
377 | return true
378 | end
379 |
380 | if err ~= errors.ZOO_NONODE then
381 | return nil, err
382 | end
383 |
384 | for p in znode:gmatch("/([^/]+)")
385 | do
386 | local part = path .. p
387 | local is_last = znode == part
388 | local ok, err = create(part, is_last and val, is_last and flags)
389 | if not ok and err ~= errors.ZOO_NODEEXISTS then
390 | return nil, err
391 | end
392 | path = part .. "/"
393 | end
394 |
395 | return true
396 | end
397 |
398 | function _M.delete(znode)
399 | local data, err = zoo_call(function()
400 | return zoo.adelete(znode)
401 | end)
402 |
403 | clear_in_cache(znode)
404 |
405 | return data and true or false, err
406 | end
407 |
408 | function _M.delete_recursive(znode)
409 | local nodes, err = childrens(znode, true)
410 | if not nodes then
411 | return nil, err
412 | end
413 |
414 | for i=1,#nodes
415 | do
416 | local ok = delete_recursive(znode .. "/" .. nodes[i])
417 | if not ok then
418 | break
419 | end
420 | end
421 |
422 | return delete(znode)
423 | end
424 |
425 | function _M.tree(znode, with_stat)
426 | local data, err = zoo_call(function()
427 | return zoo.atree(znode)
428 | end)
429 |
430 | if not data then
431 | return nil, err
432 | end
433 |
434 | local tree = unpack(data)
435 |
436 | local function traverse(zpath, node)
437 | local value, stat = node.__value, node.__stat
438 |
439 | save_in_cache("$v", zpath, value, stat)
440 | node.__value, node.__stat = nil, nil
441 |
442 | local childs = {}
443 |
444 | for k,v in pairs(node)
445 | do
446 | table.insert(childs, k)
447 | if traverse(zpath .. "/" .. k, v) == 0 and not with_stat then
448 | node[k] = v.value
449 | end
450 | end
451 |
452 | save_in_cache("$c", zpath, childs, nil)
453 |
454 | node.value, node.stat = (#value ~= 0 or #childs == 0) and value or nil, with_stat and stat or nil
455 |
456 | return #childs
457 | end
458 |
459 | traverse(znode, tree)
460 |
461 | debug(function()
462 | return "zoo tree: ", znode, "=", json_encode(tree)
463 | end)
464 |
465 | return tree
466 | end
467 |
468 | function _M.connected()
469 | return zoo.connected()
470 | end
471 |
472 | local watched = {}
473 | local job
474 |
475 | function _M.unwatch(znode, watch_type)
476 | if watch_type ~= WatcherType.DATA and watch_type ~= WatcherType.CHILDREN then
477 | return nil, "invalid watch type"
478 | end
479 |
480 | local v = watched[znode]
481 | if not v or not v[watch_type] then
482 | return nil, "not watched (unwatch can be used only from ngx.timer context or when worker_processes=1)"
483 | end
484 |
485 | local ok, err = zoo_call(function()
486 | return zoo.aunwatch(znode, watch_type)
487 | end)
488 |
489 | if ok then
490 | watched[znode][watch_type] = nil
491 |
492 | debug(function()
493 | return "unwatch: ", znode, " type=", watch_type
494 | end)
495 |
496 | return true
497 | end
498 |
499 | return nil, err
500 | end
501 |
502 | function _M.watcher_exists(znode, watch_type)
503 | return watched[znode] ~= nil and (
504 | not watch_type or watched[znode][watch_type] == watch_type
505 | )
506 | end
507 |
508 | function _M.watch(znode, watch_type, callback, ctx)
509 | if watch_type ~= WatcherType.DATA and watch_type ~= WatcherType.CHILDREN then
510 | return nil, "invalid watch type"
511 | end
512 |
513 | local data, err = zoo_call(function()
514 | return zoo.awatch(znode, watch_type)
515 | end)
516 |
517 | if not data then
518 | if err == "awatch: exists" then
519 | if watch_type == WatcherType.DATA then
520 | data, err = zoo_call(function()
521 | return zoo.aget(znode)
522 | end)
523 | else
524 | data, err = zoo_call(function()
525 | return zoo.achildrens(znode)
526 | end)
527 | end
528 | if data then
529 | return data[1]
530 | end
531 | end
532 | return nil, err
533 | end
534 |
535 | debug(function()
536 | return "watch: ", znode, " type=", watch_type
537 | end)
538 |
539 | watched[znode] = watched[znode] or {}
540 | watched[znode][watch_type] = {
541 | callback = callback,
542 | ctx = ctx,
543 | path = znode
544 | }
545 |
546 | local result = data[1]
547 |
548 | if job then
549 | return result
550 | end
551 |
552 | local function handler(premature)
553 | if premature then
554 | return
555 | end
556 |
557 | job = nil
558 |
559 | local changed, err
560 |
561 | if not zoo.connected() then
562 | goto settimer
563 | end
564 |
565 | changed, err = zoo.changed()
566 |
567 | if not changed then
568 | ngx_log(WARN, "watch: ", err)
569 | goto settimer
570 | end
571 |
572 | if #changed ~= 0 then
573 | debug(function()
574 | return "changed: ", json_encode(changed)
575 | end)
576 | end
577 |
578 | for _,c in ipairs(changed)
579 | do
580 | local node, watcher_type = unpack(c)
581 | if watched[node] then
582 | local v = watched[node][watcher_type]
583 | if v then
584 | watched[node][watcher_type] = nil
585 | if not next(watched[node]) then
586 | watched[node] = nil
587 | end
588 | pcall(v.callback, v.ctx, {
589 | path = v.path,
590 | watcher_type = watcher_type
591 | })
592 | end
593 | end
594 | end
595 |
596 | :: settimer ::
597 |
598 | if next(watched) then
599 | job = assert(ngx.timer.at(zoo_watch_interval, handler))
600 | else
601 | job = nil
602 | end
603 | end
604 |
605 | job = assert(ngx.timer.at(zoo_watch_interval, handler))
606 | return result
607 | end
608 |
609 | function _M.watch_path(znode, callback, ctx)
610 | local tree = {}
611 |
612 | tree.__value = assert(watch(znode, WatcherType.DATA, callback, ctx))
613 |
614 | for _,c in ipairs(assert(watch(znode, WatcherType.CHILDREN, callback, ctx))) do
615 | tree[c] = assert(_M.watch_path(znode .. "/" .. c, callback, ctx))
616 | end
617 |
618 | return tree
619 | end
620 |
621 | do
622 | errors = _M.errors
623 | WatcherType = _M.WatcherType
624 | set = _M.set
625 | create = _M.create
626 | delete = _M.delete
627 | delete_recursive = _M.delete_recursive
628 | childrens = _M.childrens
629 | watch = _M.watch
630 | unwatch = _M.unwatch
631 | clear_in_cache = _M.clear_in_cache
632 | end
633 |
634 |
635 | return _M
636 |
--------------------------------------------------------------------------------
/lua/zoo/api.lua:
--------------------------------------------------------------------------------
1 | local _M = {
2 | _VERSION = "2.2.1"
3 | }
4 |
5 | local zoo = require "zoo"
6 |
7 | local pcall = pcall
8 | local type = type
9 | local assert = assert
10 | local pairs = pairs
11 | local ngx_log = ngx.log
12 |
13 | function _M.get(znode)
14 | local value, stat, err = zoo.get(znode)
15 | return value and { value = value, stat = stat } or { error = err }
16 | end
17 |
18 | function _M.childrens(znode)
19 | local childs, err = zoo.childrens(znode)
20 | return childs and childs or { error = err }
21 | end
22 |
23 | function _M.set(znode, value, version)
24 | local stat, err = zoo.set(znode, value, version)
25 | return stat and { value = ngx.var.arg_value, stat = stat } or { error = err }
26 | end
27 |
28 | function _M.create(znode, value)
29 | local result, err = zoo.create(znode, value)
30 | return result and { znode = result } or { error = err }
31 | end
32 |
33 | function _M.delete(znode, recursive)
34 | local ok, err
35 |
36 | if recursive and recursive:match("[Yy1]") then
37 | ok, err = zoo.delete_recursive(znode)
38 | else
39 | ok, err = zoo.delete(znode)
40 | end
41 |
42 | return ok and { znode = "deleted" } or { error = err }
43 | end
44 |
45 | function _M.tree(znode, need_stat)
46 | local cjson = require "cjson"
47 |
48 | local subtree
49 |
50 | subtree = function(znode)
51 | local value, stat, err = zoo.get(znode)
52 | assert(value, err)
53 |
54 | local tree = {}
55 |
56 | if need_stat and stat then
57 | tree = { value = value,
58 | stat = stat }
59 | end
60 |
61 | if stat and stat.numChildren == 0 then
62 | return type(value) == "table" and {
63 | value = value
64 | } or value
65 | end
66 |
67 | if #value ~= 0 then
68 | tree.value = value
69 | end
70 |
71 | local childs, err = assert(zoo.childrens(znode))
72 |
73 | if not znode:match("/$") then
74 | znode = znode .. "/"
75 | end
76 |
77 | for _, child in pairs(childs)
78 | do
79 | local ok, r = pcall(subtree, znode .. child)
80 | if not ok then
81 | zoo.clear_in_cache(znode .. child)
82 | r = subtree(znode .. child)
83 | end
84 | tree[child] = r
85 | end
86 |
87 | return tree
88 | end
89 |
90 | local ok, r = pcall(subtree, znode)
91 |
92 | if not ok then
93 | zoo.clear_in_cache(znode)
94 | ok, r = pcall(subtree, znode)
95 | end
96 |
97 | if not ok then
98 | r = { error = r }
99 | end
100 |
101 | return r
102 | end
103 |
104 | function _M.import(root, json)
105 | local cjson = require "cjson"
106 |
107 | local create_in_depth = function(zoo_path)
108 | assert(zoo.create_path(zoo_path))
109 | end
110 |
111 | local set = function(path, value)
112 | assert(zoo.set(path, value))
113 | end
114 |
115 | local save_subtree
116 | save_subtree = function(path, subtree)
117 | for k, v in pairs(subtree)
118 | do
119 | if k ~= "value" and k ~= "stat" then
120 | local znode_path = path .. "/" .. k
121 | create_in_depth(znode_path)
122 | if type(v) == "table" then
123 | if v.value then
124 | set(znode_path, v.value)
125 | end
126 | save_subtree(znode_path, v)
127 | else
128 | set(znode_path, v)
129 | end
130 | end
131 | end
132 | end
133 |
134 | local ok, err = pcall(create_in_depth, root)
135 | if not ok then
136 | return ok, err
137 | end
138 |
139 | return pcall(save_subtree, root, cjson.decode(json))
140 | end
141 |
142 | return _M
143 |
--------------------------------------------------------------------------------
/ngx_zookeeper_lua.h:
--------------------------------------------------------------------------------
1 | #ifndef _ngx_zookeeper_lua_h_
2 | #define _ngx_zookeeper_lua_h_
3 |
4 |
5 | #include
6 |
7 |
8 | ngx_flag_t ngx_zookeeper_lua_connected();
9 | int ngx_zookeeper_lua_epoch();
10 | void * ngx_zookeeper_lua_handle();
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/ngx_zookeeper_lua_module.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 |
11 | #include "ngx_http_lua_api.h"
12 | #include "ngx_zookeeper_lua.h"
13 |
14 |
15 | ngx_module_t ngx_zookeeper_lua_module;
16 |
17 |
18 | static void *
19 | ngx_http_zookeeper_lua_create_main_conf(ngx_conf_t *cf);
20 |
21 |
22 | static ngx_int_t
23 | ngx_zookeeper_lua_init(ngx_conf_t *cf);
24 |
25 |
26 | static int
27 | ngx_zookeeper_lua_create_module(lua_State *L);
28 |
29 |
30 | ngx_int_t
31 | ngx_zookeeper_lua_init_worker(ngx_cycle_t *cycle);
32 |
33 |
34 | void
35 | ngx_zookeeper_lua_exit_worker(ngx_cycle_t *cycle);
36 |
37 |
38 | static char *
39 | ngx_http_zookeeper_lua_log_level(ngx_conf_t *cf, ngx_command_t *cmd,
40 | void *conf);
41 |
42 |
43 | static char *
44 | ngx_http_zookeeper_lua_read_only(ngx_conf_t *cf, ngx_command_t *cmd,
45 | void *conf);
46 |
47 |
48 | static char *
49 | ngx_http_zookeeper_lua_node(ngx_conf_t *cf, ngx_command_t *cmd,
50 | void *conf);
51 |
52 |
53 | static char *
54 | ngx_http_zookeeper_lua_register_port(ngx_conf_t *cf, ngx_command_t *cmd,
55 | void *conf);
56 |
57 |
58 | static char *
59 | ngx_http_zookeeper_lua_register(ngx_conf_t *cf, ngx_command_t *cmd,
60 | void *conf);
61 |
62 |
63 | static char *
64 | ngx_http_zookeeper_node_ephemeral(ngx_conf_t *cf, void *post, void *data);
65 |
66 | static ngx_conf_num_bounds_t ngx_http_zookeeper_check_inactive = {
67 | ngx_conf_check_num_bounds,
68 | 0, NGX_MAX_INT_T_VALUE
69 | };
70 |
71 | static ngx_conf_num_bounds_t ngx_http_zookeeper_check_timeout = {
72 | ngx_conf_check_num_bounds,
73 | 1, 60000
74 | };
75 |
76 |
77 | static ngx_conf_post_t ngx_http_zookeeper_ephemeral = {
78 | ngx_http_zookeeper_node_ephemeral
79 | };
80 |
81 |
82 | typedef struct
83 | {
84 | zhandle_t *handle;
85 | volatile ngx_int_t connected;
86 | const clientid_t *client_id;
87 | volatile ngx_flag_t expired;
88 | volatile int epoch;
89 | time_t last_op;
90 | } zookeeper_t;
91 |
92 |
93 | typedef struct {
94 | ngx_str_t path;
95 | int watch_type;
96 | volatile ngx_flag_t changed;
97 | } watched_t;
98 |
99 | typedef struct
100 | {
101 | ngx_addr_t *addrs;
102 | ngx_uint_t naddrs;
103 | ngx_str_t hosts;
104 | ngx_int_t recv_timeout;
105 | int init_flags;
106 | ngx_array_t *nodes;
107 | ZooLogLevel log_level;
108 | ngx_int_t inactive_time;
109 |
110 | zookeeper_t zoo;
111 | ngx_event_t ev;
112 | ngx_array_t *watched;
113 | ngx_atomic_t lock;
114 | } ngx_http_zookeeper_lua_main_conf_t;
115 |
116 |
117 | static ngx_command_t ngx_http_zookeeper_lua_commands[] = {
118 |
119 | { ngx_string("zookeeper"),
120 | NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
121 | ngx_conf_set_str_slot,
122 | NGX_HTTP_MAIN_CONF_OFFSET,
123 | offsetof(ngx_http_zookeeper_lua_main_conf_t, hosts),
124 | NULL },
125 |
126 | { ngx_string("zookeeper_log_level"),
127 | NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
128 | ngx_http_zookeeper_lua_log_level,
129 | 0,
130 | 0,
131 | NULL },
132 |
133 | { ngx_string("zookeeper_recv_timeout"),
134 | NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
135 | ngx_conf_set_num_slot,
136 | NGX_HTTP_MAIN_CONF_OFFSET,
137 | offsetof(ngx_http_zookeeper_lua_main_conf_t, recv_timeout),
138 | &ngx_http_zookeeper_check_timeout },
139 |
140 | { ngx_string("zookeeper_ethemeral_node"),
141 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|
142 | NGX_CONF_TAKE2|NGX_CONF_TAKE3,
143 | ngx_http_zookeeper_lua_node,
144 | 0,
145 | 0,
146 | &ngx_http_zookeeper_ephemeral },
147 |
148 | { ngx_string("zookeeper_ephemeral_node"),
149 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|
150 | NGX_CONF_TAKE2|NGX_CONF_TAKE3,
151 | ngx_http_zookeeper_lua_node,
152 | 0,
153 | 0,
154 | &ngx_http_zookeeper_ephemeral },
155 |
156 | { ngx_string("zookeeper_node"),
157 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|
158 | NGX_CONF_TAKE2|NGX_CONF_TAKE3,
159 | ngx_http_zookeeper_lua_node,
160 | 0,
161 | 0,
162 | NULL },
163 |
164 | { ngx_string("zookeeper_register_port"),
165 | NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2|NGX_CONF_TAKE3|NGX_CONF_TAKE4,
166 | ngx_http_zookeeper_lua_register_port,
167 | 0,
168 | 0,
169 | NULL },
170 |
171 | { ngx_string("zookeeper_register"),
172 | NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3,
173 | ngx_http_zookeeper_lua_register,
174 | 0,
175 | 0,
176 | NULL },
177 |
178 | { ngx_string("zookeeper_read_only"),
179 | NGX_HTTP_MAIN_CONF|NGX_CONF_NOARGS,
180 | ngx_http_zookeeper_lua_read_only,
181 | 0,
182 | 0,
183 | NULL },
184 |
185 | { ngx_string("zookeeper_inactive_time"),
186 | NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
187 | ngx_conf_set_num_slot,
188 | NGX_HTTP_MAIN_CONF_OFFSET,
189 | offsetof(ngx_http_zookeeper_lua_main_conf_t, inactive_time),
190 | &ngx_http_zookeeper_check_inactive },
191 |
192 | ngx_null_command
193 | };
194 |
195 |
196 | static ngx_http_module_t ngx_zookeeper_lua_ctx = {
197 | NULL, /* preconfiguration */
198 | ngx_zookeeper_lua_init, /* postconfiguration */
199 | ngx_http_zookeeper_lua_create_main_conf, /* create main configuration */
200 | NULL, /* init main configuration */
201 | NULL, /* create server configuration */
202 | NULL, /* merge server configuration */
203 | NULL, /* create location configuration */
204 | NULL /* merge location configuration */
205 | };
206 |
207 |
208 | ngx_module_t ngx_zookeeper_lua_module = {
209 | NGX_MODULE_V1,
210 | &ngx_zookeeper_lua_ctx, /* module context */
211 | ngx_http_zookeeper_lua_commands, /* module directives */
212 | NGX_HTTP_MODULE, /* module type */
213 | NULL, /* init master */
214 | NULL, /* init module */
215 | ngx_zookeeper_lua_init_worker, /* init process */
216 | NULL, /* init thread */
217 | NULL, /* exit thread */
218 | ngx_zookeeper_lua_exit_worker, /* exit process */
219 | NULL, /* exit master */
220 | NGX_MODULE_V1_PADDING
221 | };
222 |
223 |
224 | typedef struct {
225 | ngx_array_t *path;
226 | char *value;
227 | char *node;
228 | char *data;
229 | int epoch;
230 | ngx_flag_t ephemeral;
231 | const char *fmt;
232 | const char *update_fmt;
233 | ngx_flag_t may_be_updated;
234 | ngx_int_t timestamp;
235 | } ngx_zoo_node_t;
236 |
237 |
238 | static void
239 | ngx_zookeeper_monitor(ngx_event_t *ev);
240 |
241 |
242 | static void *
243 | ngx_http_zookeeper_lua_create_main_conf(ngx_conf_t *cf)
244 | {
245 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
246 | ngx_url_t u;
247 | ngx_uint_t j;
248 | ngx_connection_t *c;
249 |
250 | zmcf = ngx_pcalloc(cf->pool,
251 | sizeof(ngx_http_zookeeper_lua_main_conf_t));
252 | if (zmcf == NULL)
253 | return NULL;
254 |
255 | zmcf->log_level = ZOO_LOG_LEVEL_ERROR;
256 | zmcf->recv_timeout = NGX_CONF_UNSET;
257 | zmcf->inactive_time = NGX_CONF_UNSET;
258 | zmcf->init_flags = 0;
259 | zmcf->nodes = ngx_array_create(cf->pool, 1000, sizeof(ngx_zoo_node_t));
260 | if (zmcf->nodes == NULL)
261 | return NULL;
262 |
263 | ngx_memzero(&u, sizeof(ngx_url_t));
264 |
265 | u.url = cf->cycle->hostname;
266 | u.default_port = 1;
267 |
268 | if (ngx_parse_url(cf->pool, &u) == NGX_OK) {
269 |
270 | zmcf->addrs = u.addrs;
271 | zmcf->naddrs = u.naddrs;
272 |
273 | for (j = 0; j < u.naddrs; j++)
274 | zmcf->addrs[j].name.len -= 2;
275 | }
276 |
277 | zmcf->zoo.expired = 1;
278 | zmcf->zoo.epoch = 1;
279 | zmcf->zoo.connected = NGX_DECLINED;
280 |
281 | zmcf->ev.handler = ngx_zookeeper_monitor;
282 | c = ngx_pcalloc(cf->pool, sizeof(ngx_connection_t));
283 | if (c == NULL)
284 | return NULL;
285 | c->fd = -1;
286 | zmcf->ev.data = c;
287 |
288 | zmcf->watched = ngx_array_create(cf->pool, 1000, sizeof(watched_t));
289 | if (zmcf->watched == NULL)
290 | return NULL;
291 |
292 | return zmcf;
293 | }
294 |
295 |
296 | static zookeeper_t *
297 | ngx_http_zmcf()
298 | {
299 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
300 |
301 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
302 | ngx_zookeeper_lua_module);
303 |
304 | return &zmcf->zoo;
305 | }
306 |
307 | static void
308 | ngx_http_zookeeper_check_mon(void)
309 | {
310 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
311 |
312 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
313 | ngx_zookeeper_lua_module);
314 |
315 | if (!zmcf->ev.timer_set) {
316 | zmcf->zoo.last_op = ngx_time();
317 | ngx_zookeeper_monitor(&zmcf->ev);
318 | }
319 | }
320 |
321 |
322 | static ngx_flag_t
323 | str_eq(ngx_str_t s1, ngx_str_t s2)
324 | {
325 | return ngx_memn2cmp(s1.data, s2.data, s1.len, s2.len) == 0;
326 | }
327 |
328 |
329 | static char *
330 | ngx_http_zookeeper_lua_log_level(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
331 | {
332 | ngx_http_zookeeper_lua_main_conf_t *zmcf = conf;
333 | ngx_str_t log_level;
334 |
335 | static const ngx_str_t LOG_ERR = ngx_string("error");
336 | static const ngx_str_t LOG_INFO = ngx_string("warn");
337 | static const ngx_str_t LOG_WARN = ngx_string("info");
338 | static const ngx_str_t LOG_DEBUG = ngx_string("debug");
339 |
340 | log_level = ((ngx_str_t *) cf->args->elts)[1];
341 | ngx_strlow(log_level.data, log_level.data, log_level.len);
342 |
343 | if (str_eq(LOG_ERR, log_level))
344 |
345 | zmcf->log_level = ZOO_LOG_LEVEL_ERROR;
346 | else if (str_eq(LOG_WARN, log_level))
347 |
348 | zmcf->log_level = ZOO_LOG_LEVEL_WARN;
349 | else if (str_eq(LOG_INFO, log_level))
350 |
351 | zmcf->log_level = ZOO_LOG_LEVEL_INFO;
352 | else if (str_eq(LOG_DEBUG, log_level))
353 |
354 | zmcf->log_level = ZOO_LOG_LEVEL_DEBUG;
355 | else {
356 |
357 | ngx_log_error(NGX_LOG_ERR, cf->log, 0,
358 | "invalid zookeeper_log_level value (error, warn, info, debug)");
359 | return NGX_CONF_ERROR;
360 | }
361 |
362 | zoo_set_debug_level(zmcf->log_level);
363 |
364 | return NGX_CONF_OK;
365 | }
366 |
367 |
368 | static char *
369 | ngx_http_zookeeper_lua_read_only(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
370 | {
371 | // ngx_http_zookeeper_lua_module_main_conf_t *zookeeper_conf = conf;
372 | // Temporary unsupported
373 | // zookeeper_conf->init_flags = ZOO_READONLY;
374 | return NGX_CONF_OK;
375 | }
376 |
377 |
378 | static ngx_array_t *
379 | path_parse(ngx_pool_t *pool, ngx_str_t znode)
380 | {
381 | ngx_array_t *a;
382 | u_char *s;
383 | u_char **sub;
384 |
385 | a = ngx_array_create(pool, 20, sizeof(u_char *));
386 | if (a == NULL)
387 | return NULL;
388 |
389 | for (s = znode.data + 1;
390 | s <= znode.data + znode.len;
391 | s++) {
392 |
393 | if (s == znode.data + znode.len || *s == '/') {
394 |
395 | sub = ngx_array_push(a);
396 | if (sub == NULL)
397 | return NULL;
398 |
399 | *sub = ngx_pcalloc(pool, s - znode.data + 1);
400 | if (*sub == NULL)
401 | return NULL;
402 |
403 | ngx_memcpy(*sub, znode.data, s - znode.data);
404 | }
405 | }
406 |
407 | return a;
408 | }
409 |
410 |
411 | static char *
412 | concat(ngx_pool_t *pool, ngx_str_t l, ngx_str_t r, char sep)
413 | {
414 | u_char *s;
415 |
416 | s = ngx_pcalloc(pool, l.len + r.len + 2);
417 | if (s == NULL)
418 | return NULL;
419 |
420 | ngx_snprintf(s, l.len + r.len + 2, "%V%c%V", &l, sep, &r);
421 |
422 | return (char *) s;
423 | }
424 |
425 |
426 | static char *
427 | cstr(ngx_pool_t *pool, ngx_str_t s)
428 | {
429 | u_char *cs;
430 |
431 | cs = ngx_pcalloc(pool, s.len + 1);
432 | if (cs == NULL)
433 | return NULL;
434 |
435 | ngx_memcpy(cs, s.data, s.len);
436 |
437 | return (char *) cs;
438 | }
439 |
440 |
441 | static ngx_flag_t
442 | exists_node(ngx_http_zookeeper_lua_main_conf_t *zmcf, const char *znode)
443 | {
444 | ngx_uint_t j;
445 | ngx_zoo_node_t *nodes;
446 |
447 | nodes = zmcf->nodes->elts;
448 |
449 | for (j = 0; j < zmcf->nodes->nelts; j++)
450 | if (ngx_strcmp(znode, nodes[j].node) == 0)
451 | return 1;
452 |
453 | return 0;
454 | }
455 |
456 |
457 | static char *
458 | ngx_http_zookeeper_lua_node(ngx_conf_t *cf, ngx_command_t *cmd,
459 | void *conf)
460 | {
461 | ngx_http_zookeeper_lua_main_conf_t *zmcf = conf;
462 | ngx_str_t *values = cf->args->elts;
463 | ngx_zoo_node_t *node;
464 | ngx_conf_post_t *post;
465 |
466 | node = ngx_array_push(zmcf->nodes);
467 | zmcf->nodes->nelts--;
468 | ngx_memzero(node, sizeof(ngx_zoo_node_t));
469 |
470 | node->path = path_parse(cf->pool, values[1]);
471 | node->value = cstr(cf->pool, values[2]);
472 | node->node = concat(cf->pool, values[1], values[2], '/');
473 | if (node->node == NULL)
474 | return NGX_CONF_ERROR;
475 |
476 | if (exists_node(zmcf, node->node))
477 | return NGX_CONF_OK;
478 |
479 | node->epoch = 0;
480 | node->ephemeral = 0;
481 | node->fmt = "Node has been created: %s = %s";
482 | node->update_fmt = "Node has been updated: %s = %s";
483 | node->may_be_updated = 1;
484 |
485 | if (cf->args->nelts == 4) {
486 |
487 | node->data = cstr(cf->pool, values[3]);
488 | if (node->data == NULL)
489 | return NGX_CONF_ERROR;
490 |
491 | } else
492 | node->data = "";
493 |
494 | zmcf->nodes->nelts++;
495 |
496 | if (cmd->post) {
497 |
498 | post = cmd->post;
499 | return post->post_handler(cf, post, node);
500 | }
501 |
502 | return NGX_CONF_OK;
503 | }
504 |
505 |
506 | static char *
507 | ngx_http_zookeeper_node_ephemeral(ngx_conf_t *cf, void *post, void *data)
508 | {
509 | ngx_zoo_node_t *node = data;
510 |
511 | node->ephemeral = 1;
512 | node->fmt = "Ephemeral node has been created: %s = %s";
513 | node->update_fmt = "Ephemeral node has been updated: %s = %s";
514 | node->may_be_updated = 1;
515 |
516 | return NGX_CONF_OK;
517 | }
518 |
519 |
520 | static char *
521 | ngx_http_zookeeper_lua_register_port(ngx_conf_t *cf, ngx_command_t *cmd,
522 | void *conf)
523 | {
524 | ngx_http_zookeeper_lua_main_conf_t *zmcf = conf;
525 | ngx_str_t *values = cf->args->elts;
526 | ngx_zoo_node_t *node;
527 | ngx_str_t val;
528 | ngx_uint_t j;
529 |
530 | for (j = 0; j < zmcf->naddrs; j++) {
531 |
532 | node = ngx_array_push(zmcf->nodes);
533 | zmcf->nodes->nelts--;
534 | ngx_memzero(node, sizeof(ngx_zoo_node_t));
535 |
536 | node->path = path_parse(cf->pool, values[1]);
537 | node->value = concat(cf->pool, zmcf->addrs[j].name, values[2], ':');
538 | if (node->value == NULL)
539 | return NGX_CONF_ERROR;
540 |
541 | val.data = (u_char *) node->value;
542 | val.len = strlen(node->value);
543 | node->node = concat(cf->pool, values[1], val, '/');
544 | if (node->node == NULL)
545 | return NGX_CONF_ERROR;
546 |
547 | if (exists_node(zmcf, node->node))
548 | continue;
549 |
550 | node->epoch = 0;
551 | node->ephemeral = 1;
552 | node->fmt = "Nginx has been registered, instance: %s = %s";
553 |
554 | if (cf->args->nelts >= 4) {
555 |
556 | node->data = cstr(cf->pool, values[3]);
557 | if (node->data == NULL)
558 | return NGX_CONF_ERROR;
559 |
560 | if (cf->args->nelts == 5)
561 | node->timestamp = ngx_time() + ngx_max(0, ngx_atoi(values[4].data, values[4].len));
562 | } else
563 | node->data = "";
564 |
565 | zmcf->nodes->nelts++;
566 | }
567 |
568 | return NGX_CONF_OK;
569 | }
570 |
571 |
572 | static char *
573 | ngx_http_zookeeper_lua_register(ngx_conf_t *cf, ngx_command_t *cmd,
574 | void *conf)
575 | {
576 | ngx_http_zookeeper_lua_main_conf_t *zmcf = conf;
577 | ngx_str_t *values = cf->args->elts;
578 | ngx_zoo_node_t *node;
579 | ngx_uint_t j;
580 |
581 | for (j = 0; j < zmcf->naddrs; j++) {
582 |
583 | node = ngx_array_push(zmcf->nodes);
584 | zmcf->nodes->nelts--;
585 | ngx_memzero(node, sizeof(ngx_zoo_node_t));
586 |
587 | node->path = path_parse(cf->pool, values[1]);
588 | node->value = cstr(cf->pool, zmcf->addrs[j].name);
589 |
590 | node->node = concat(cf->pool, values[1], zmcf->addrs[j].name, '/');
591 | if (node->node == NULL)
592 | return NGX_CONF_ERROR;
593 |
594 | if (exists_node(zmcf, node->node))
595 | continue;
596 |
597 | node->epoch = 0;
598 | node->ephemeral = 1;
599 | node->fmt = "Nginx has been registered, instance: %s = %s";
600 |
601 | if (cf->args->nelts >= 3) {
602 |
603 | node->data = cstr(cf->pool, values[2]);
604 | if (node->data == NULL)
605 | return NGX_CONF_ERROR;
606 |
607 | if (cf->args->nelts == 4)
608 | node->timestamp = ngx_time() + ngx_max(0, ngx_atoi(values[3].data, values[3].len));
609 | } else
610 | node->data = "";
611 |
612 | zmcf->nodes->nelts++;
613 | }
614 |
615 | return NGX_CONF_OK;
616 | }
617 |
618 |
619 | ngx_flag_t
620 | ngx_zookeeper_lua_connected()
621 | {
622 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
623 |
624 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
625 | ngx_zookeeper_lua_module);
626 |
627 | return zmcf->hosts.len != 0 /* not configured */ &&
628 | (!zmcf->ev.timer_set /* suspended */ || (zmcf->zoo.handle && zmcf->zoo.connected != NGX_ERROR));
629 | }
630 |
631 |
632 | int
633 | ngx_zookeeper_lua_epoch()
634 | {
635 | return ngx_http_zmcf()->epoch;
636 | }
637 |
638 |
639 | void *
640 | ngx_zookeeper_lua_handle()
641 | {
642 | return ngx_http_zmcf()->handle;
643 | }
644 |
645 |
646 | ngx_int_t
647 | ngx_zookeeper_lua_init(ngx_conf_t *cf)
648 | {
649 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
650 |
651 | if (ngx_http_lua_add_package_preload(cf, "ngx.zookeeper",
652 | ngx_zookeeper_lua_create_module)
653 | != NGX_OK)
654 | return NGX_ERROR;
655 |
656 | zmcf = ngx_http_conf_get_module_main_conf(cf, ngx_zookeeper_lua_module);
657 |
658 | ngx_conf_init_value(zmcf->recv_timeout, 10000);
659 |
660 | return NGX_OK;
661 | }
662 |
663 |
664 | static void
665 | ngx_log_message(const char *s)
666 | {
667 | ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0, s);
668 | }
669 |
670 |
671 | #if (NGX_DEBUG)
672 |
673 | static const char *
674 | str_type(int type)
675 | {
676 | if (type == ZOO_CREATED_EVENT)
677 | return "CREATED_EVENT";
678 | if (type == ZOO_DELETED_EVENT)
679 | return "DELETED_EVENT";
680 | if (type == ZOO_CHANGED_EVENT)
681 | return "CHANGED_EVENT";
682 | if (type == ZOO_CHILD_EVENT)
683 | return "CHILD_EVENT";
684 | if (type == ZOO_SESSION_EVENT)
685 | return "SESSION_EVENT";
686 | if (type == ZOO_NOTWATCHING_EVENT)
687 | return "NOTWATCHING_EVENT";
688 |
689 | return "UNKNOWN_EVENT_TYPE";
690 | }
691 |
692 | #endif
693 |
694 |
695 | static const char *
696 | ngx_zerr(int rc)
697 | {
698 | if (rc == ZOK)
699 | return "OK";
700 | if (rc == ZSYSTEMERROR)
701 | return "System error";
702 | if (rc == ZRUNTIMEINCONSISTENCY)
703 | return "Runtime inconsistency";
704 | if (rc == ZDATAINCONSISTENCY)
705 | return "Data inconsistency";
706 | if (rc == ZCONNECTIONLOSS)
707 | return "Connection to the server has been lost";
708 | if (rc == ZMARSHALLINGERROR)
709 | return "Error while marshalling or unmarshalling data";
710 | if (rc == ZUNIMPLEMENTED)
711 | return "Operation not implemented";
712 | if (rc == ZOPERATIONTIMEOUT)
713 | return "Operation timeout";
714 | if (rc == ZBADARGUMENTS)
715 | return "Invalid argument";
716 | if (rc == ZINVALIDSTATE)
717 | return "Invalid zhandle state";
718 | if (rc == ZAPIERROR)
719 | return "API error";
720 | if (rc == ZNONODE)
721 | return "Znode does not exist";
722 | if (rc == ZNOAUTH)
723 | return "Not authenticated";
724 | if (rc == ZBADVERSION)
725 | return "Version conflict";
726 | if (rc == ZNOCHILDRENFOREPHEMERALS)
727 | return "Ephemeral nodes may not have children";
728 | if (rc == ZNODEEXISTS)
729 | return "Znode already exists";
730 | if (rc == ZNOTEMPTY)
731 | return "The znode has children";
732 | if (rc == ZSESSIONEXPIRED)
733 | return "The session has been expired by the server";
734 | if (rc == ZINVALIDCALLBACK)
735 | return "Invalid callback specified";
736 | if (rc == ZINVALIDACL)
737 | return "Invalid ACL specified";
738 | if (rc == ZAUTHFAILED)
739 | return "Client authentication failed";
740 | if (rc == ZCLOSING)
741 | return "ZooKeeper session is closing";
742 | if (rc == ZNOTHING)
743 | return "No response from server";
744 | if (rc == ZSESSIONMOVED)
745 | return "Session moved to a different server";
746 |
747 | return "Unknown";
748 | }
749 |
750 | static void
751 | ngx_zookeeper_register_set_ready(int rc, const struct Stat *stat, const void *data)
752 | {
753 | ngx_zoo_node_t *node = (ngx_zoo_node_t *) data;
754 |
755 | if (rc == ZOK) {
756 |
757 | if (!node->ephemeral)
758 | node->epoch = ngx_http_zmcf()->epoch;
759 |
760 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0,
761 | node->update_fmt, node->node, node->data);
762 |
763 | return;
764 | }
765 |
766 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
767 | "Zookeeper can't create %s node %s: %s",
768 | node->ephemeral ? "ephemeral" : "regular",
769 | node->node, ngx_zerr(rc));
770 | }
771 |
772 |
773 | static void
774 | ngx_zookeeper_register_create_ready(int rc, const char *value, const void *data)
775 | {
776 | ngx_zoo_node_t *node;
777 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
778 |
779 | node = (ngx_zoo_node_t *) data;
780 |
781 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
782 | ngx_zookeeper_lua_module);
783 |
784 | if (rc == ZOK || rc == ZNODEEXISTS) {
785 |
786 | if (node == NULL)
787 | return;
788 |
789 | if (rc == ZOK) {
790 |
791 | node->epoch = ngx_http_zmcf()->epoch;
792 |
793 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0,
794 | node->fmt, node->node, node->data);
795 |
796 | return;
797 |
798 | } else if (node->may_be_updated) {
799 |
800 | rc = zoo_aset(zmcf->zoo.handle, node->node, node->data,
801 | strlen(node->data), -1, ngx_zookeeper_register_set_ready, node);
802 |
803 | if (rc != ZOK)
804 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
805 | "Zookeeper: error register instance: %s",
806 | ngx_zerr(rc));
807 |
808 | return;
809 | }
810 | }
811 |
812 | if (node != NULL) {
813 |
814 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
815 | "Zookeeper can't create %s node %s: %s",
816 | node->ephemeral ? "ephemeral" : "regular",
817 | node->node, ngx_zerr(rc));
818 | } else {
819 |
820 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
821 | "Zookeeper can't create node %s: %s",
822 | value != NULL ? value : "???", ngx_zerr(rc));
823 | }
824 | }
825 |
826 |
827 | static ngx_int_t
828 | initialize(volatile ngx_cycle_t *cycle);
829 |
830 |
831 | static void
832 | ngx_zookeeper_delete_ready(int rc, const void *data);
833 |
834 | static void
835 | ngx_zookeeper_register_node(ngx_log_t *log, ngx_zoo_node_t *node)
836 | {
837 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
838 | const char **path;
839 | int rc;
840 | ngx_uint_t j;
841 |
842 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
843 | ngx_zookeeper_lua_module);
844 |
845 | path = node->path->elts;
846 |
847 | for (j = 0; j < node->path->nelts; ++j) {
848 |
849 | rc = zoo_acreate(zmcf->zoo.handle, path[j], "", 0,
850 | &ZOO_OPEN_ACL_UNSAFE, 0, ngx_zookeeper_register_create_ready,
851 | NULL);
852 |
853 | if (rc != ZOK) {
854 |
855 | ngx_log_error(NGX_LOG_ERR, log, 0,
856 | "Zookeeper: error create node %s : %s",
857 | path[j], ngx_zerr(rc));
858 | }
859 | }
860 |
861 | rc = zoo_acreate(zmcf->zoo.handle, node->node, node->data,
862 | strlen(node->data), &ZOO_OPEN_ACL_UNSAFE,
863 | node->ephemeral ? ZOO_EPHEMERAL : 0,
864 | ngx_zookeeper_register_create_ready, node);
865 |
866 | if (rc != ZOK)
867 | ngx_log_error(NGX_LOG_ERR, log, 0,
868 | "Zookeeper: error register instance: %s",
869 | ngx_zerr(rc));
870 | }
871 |
872 | static void
873 | ngx_zookeeper_monitor(ngx_event_t *ev)
874 | {
875 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
876 | ngx_zoo_node_t *nodes;
877 | ngx_uint_t i;
878 | ngx_int_t delay;
879 |
880 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
881 | ngx_zookeeper_lua_module);
882 | nodes = (ngx_zoo_node_t *) zmcf->nodes->elts;
883 | delay = zmcf->recv_timeout * 2;
884 |
885 | if (zmcf->inactive_time != NGX_CONF_UNSET /* suspend after inactive time */
886 | && zmcf->nodes->nelts == 0 /* nothing to register */
887 | && zmcf->watched->nelts == 0 /* nothing to watch */
888 | && zmcf->zoo.handle)
889 | {
890 | if (zmcf->zoo.last_op + zmcf->inactive_time < ngx_time()) {
891 |
892 | ngx_log_error(NGX_LOG_INFO, ev->log, 0,
893 | "Zookeeper: inactive time, disconnect");
894 |
895 | zookeeper_close(zmcf->zoo.handle);
896 |
897 | zmcf->zoo.handle = NULL;
898 | zmcf->zoo.client_id = NULL;
899 | zmcf->zoo.expired = 1;
900 | zmcf->zoo.connected = NGX_DECLINED;
901 |
902 | return;
903 | }
904 | }
905 |
906 | if (zmcf->zoo.expired) {
907 |
908 | if (zmcf->zoo.handle != NULL) {
909 |
910 | zookeeper_close(zmcf->zoo.handle);
911 | zmcf->zoo.handle = NULL;
912 | zmcf->zoo.client_id = 0;
913 | }
914 |
915 | if (initialize(ngx_cycle) != NGX_OK)
916 | goto settimer;
917 | }
918 |
919 | if (ngx_worker != 0)
920 | goto settimer;
921 |
922 | if (zmcf->nodes->nelts == 0)
923 | goto settimer;
924 |
925 | if (zmcf->zoo.connected == NGX_ERROR)
926 | goto settimer;
927 |
928 | for (i = 0; i < zmcf->nodes->nelts; i++) {
929 | if (nodes[i].timestamp > ngx_time())
930 | delay = ngx_min(delay, nodes[i].timestamp - ngx_time());
931 | if (zmcf->zoo.epoch > nodes[i].epoch && nodes[i].timestamp <= ngx_time())
932 | ngx_zookeeper_register_node(ev->log, nodes + i);
933 | }
934 |
935 | settimer:
936 |
937 | if (ngx_exiting || ngx_terminate || ngx_quit)
938 | // cleanup
939 | ngx_memset(ev, 0, sizeof(ngx_event_t));
940 | else
941 | ngx_add_timer(ev, delay);
942 | }
943 |
944 |
945 | static void
946 | ngx_zookeeper_create_ready(int rc, const char *value, const void *p);
947 |
948 |
949 | static void
950 | session_watcher(zhandle_t *zh,
951 | int type,
952 | int state,
953 | const char *path,
954 | void* context);
955 |
956 |
957 | static ngx_int_t
958 | initialize(volatile ngx_cycle_t *cycle)
959 | {
960 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
961 |
962 | zmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_zookeeper_lua_module);
963 |
964 | if (zmcf->zoo.connected == NGX_DECLINED)
965 | zmcf->zoo.connected = NGX_BUSY;
966 |
967 | zmcf->zoo.handle = zookeeper_init2((const char *) zmcf->hosts.data,
968 | session_watcher,
969 | zmcf->recv_timeout,
970 | zmcf->zoo.client_id,
971 | 0,
972 | zmcf->init_flags,
973 | ngx_log_message);
974 |
975 | if (zmcf->zoo.handle == NULL) {
976 |
977 | u_char err[1024];
978 |
979 | ngx_log_error(NGX_LOG_ERR, cycle->log, 0,
980 | "Zookeeper: error create zookeeper handle: %s",
981 | ngx_strerror(errno, err, sizeof(err)));
982 |
983 | zmcf->zoo.connected = NGX_ERROR;
984 |
985 | return NGX_ERROR;
986 | }
987 |
988 | zmcf->zoo.expired = 0;
989 |
990 | ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
991 | "Zookeeper: connecting");
992 |
993 | return NGX_OK;
994 | }
995 |
996 |
997 | static void
998 | session_watcher(zhandle_t *zh,
999 | int type,
1000 | int state,
1001 | const char *path,
1002 | void *p)
1003 | {
1004 | zookeeper_t *zoo = ngx_http_zmcf();
1005 |
1006 | if (type == ZOO_SESSION_EVENT) {
1007 |
1008 | if (state == ZOO_CONNECTED_STATE) {
1009 |
1010 | zoo->connected = NGX_OK;
1011 | zoo->epoch = zoo->epoch + 1;
1012 | zoo->client_id = zoo_client_id(zh);
1013 |
1014 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0,
1015 | "Zookeeper: connected");
1016 |
1017 | } else if (state == ZOO_CONNECTING_STATE) {
1018 |
1019 | if (zoo->connected != NGX_ERROR) {
1020 | ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0,
1021 | "Zookeeper: disconnected");
1022 | }
1023 |
1024 | zoo->connected = NGX_ERROR;
1025 |
1026 | } else if (state == ZOO_EXPIRED_SESSION_STATE) {
1027 |
1028 | if (zh != NULL) {
1029 |
1030 | ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0,
1031 | "Zookeeper: session has been expired");
1032 |
1033 | zoo->connected = NGX_ERROR;
1034 | zoo->expired = 1;
1035 | zoo->client_id = NULL;
1036 | }
1037 | }
1038 | }
1039 |
1040 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1041 | "Zookeeper event: %s, %d",
1042 | str_type(type), state);
1043 | }
1044 |
1045 |
1046 | ngx_int_t
1047 | ngx_zookeeper_lua_init_worker(ngx_cycle_t *cycle)
1048 | {
1049 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
1050 |
1051 | if (ngx_process != NGX_PROCESS_WORKER && ngx_process != NGX_PROCESS_SINGLE)
1052 | return NGX_OK;
1053 |
1054 | zmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_zookeeper_lua_module);
1055 |
1056 | if (zmcf == NULL || zmcf->hosts.len == 0)
1057 | return NGX_OK;
1058 |
1059 | ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
1060 | "Zookeeper connector has been initialized in %s mode",
1061 | zmcf->init_flags == ZOO_READONLY ? "ro" : "rw");
1062 |
1063 | zmcf->ev.log = cycle->log;
1064 |
1065 | if (ngx_worker != 0) {
1066 | zmcf->nodes->nelts = 0;
1067 | zmcf->nodes->elts = NULL;
1068 | }
1069 |
1070 | if (zmcf->inactive_time == NGX_CONF_UNSET || zmcf->nodes->nelts != 0) {
1071 | initialize(cycle);
1072 | ngx_add_timer(&zmcf->ev, 1000);
1073 | } else {
1074 | ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "Zookeeper connector suspended");
1075 | }
1076 |
1077 | return NGX_OK;
1078 | }
1079 |
1080 |
1081 | void
1082 | ngx_zookeeper_lua_exit_worker(ngx_cycle_t *cycle)
1083 | {
1084 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
1085 |
1086 | zmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_zookeeper_lua_module);
1087 |
1088 | if (zmcf->ev.timer_set)
1089 | ngx_del_timer(&zmcf->ev);
1090 |
1091 | if (zmcf->zoo.handle == NULL)
1092 | return;
1093 |
1094 | zookeeper_close(zmcf->zoo.handle);
1095 | zmcf->zoo.handle = NULL;
1096 |
1097 | ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
1098 | "Zookeeper connector has been destroyed");
1099 | }
1100 |
1101 |
1102 | static int ngx_zookeeper_connected(lua_State *L);
1103 |
1104 | static int ngx_zookeeper_suspended(lua_State *L);
1105 |
1106 | static int ngx_zookeeper_resume(lua_State *L);
1107 |
1108 | static int ngx_zookeeper_aget(lua_State *L);
1109 |
1110 | static int ngx_zookeeper_aset(lua_State *L);
1111 |
1112 | static int ngx_zookeeper_aget_childrens(lua_State *L);
1113 |
1114 | static int ngx_zookeeper_acreate(lua_State *L);
1115 |
1116 | static int ngx_zookeeper_adelete(lua_State *L);
1117 |
1118 | static int ngx_zookeeper_atree(lua_State *L);
1119 |
1120 | static int ngx_zookeeper_check_completition(lua_State *L);
1121 |
1122 | static int ngx_zookeeper_timeout(lua_State *L);
1123 |
1124 | static int ngx_zookeeper_addrs(lua_State *L);
1125 |
1126 | static int ngx_zookeeper_hostname(lua_State *L);
1127 |
1128 | static int ngx_zookeeper_awatch(lua_State *L);
1129 |
1130 | static int ngx_zookeeper_aunwatch(lua_State *L);
1131 |
1132 | static int ngx_zookeeper_changed(lua_State *L);
1133 |
1134 | #ifndef OPENRESTY_LUAJIT
1135 | #if !defined LUA_VERSION_NUM || LUA_VERSION_NUM < 502
1136 |
1137 | static void
1138 | luaL_setfuncs(lua_State *l, const luaL_Reg *reg, int nup)
1139 | {
1140 | int i;
1141 |
1142 | luaL_checkstack(l, nup, "too many upvalues");
1143 |
1144 | for (; reg->name != NULL; reg++) {
1145 | for (i = 0; i < nup; i++) {
1146 | lua_pushvalue(l, -nup);
1147 | }
1148 | lua_pushcclosure(l, reg->func, nup);
1149 | lua_setfield(l, -(nup + 2), reg->name);
1150 | }
1151 |
1152 | lua_pop(l, nup);
1153 | }
1154 |
1155 | #endif
1156 | #endif
1157 |
1158 |
1159 | static int
1160 | delete(lua_State *L);
1161 |
1162 |
1163 | static void
1164 | ngx_zookeeper_register_gc(lua_State *L)
1165 | {
1166 | luaL_Reg regZoo[] =
1167 | {
1168 | { "__gc", delete },
1169 | { NULL, NULL }
1170 | };
1171 |
1172 | luaL_newmetatable(L, "ngx_zoo");
1173 | luaL_setfuncs(L, regZoo, 0);
1174 | lua_pushvalue(L, -1);
1175 | lua_setfield(L, -1, "__index");
1176 |
1177 | lua_pop(L, 1);
1178 | }
1179 |
1180 |
1181 | static int
1182 | ngx_zookeeper_lua_create_module(lua_State *L)
1183 | {
1184 | ngx_zookeeper_register_gc(L);
1185 |
1186 | lua_newtable(L);
1187 |
1188 | lua_pushcfunction(L, ngx_zookeeper_connected);
1189 | lua_setfield(L, -2, "connected");
1190 |
1191 | lua_pushcfunction(L, ngx_zookeeper_suspended);
1192 | lua_setfield(L, -2, "suspended");
1193 |
1194 | lua_pushcfunction(L, ngx_zookeeper_resume);
1195 | lua_setfield(L, -2, "resume");
1196 |
1197 | lua_pushcfunction(L, ngx_zookeeper_aget);
1198 | lua_setfield(L, -2, "aget");
1199 |
1200 | lua_pushcfunction(L, ngx_zookeeper_aset);
1201 | lua_setfield(L, -2, "aset");
1202 |
1203 | lua_pushcfunction(L, ngx_zookeeper_aget_childrens);
1204 | lua_setfield(L, -2, "achildrens");
1205 |
1206 | lua_pushcfunction(L, ngx_zookeeper_acreate);
1207 | lua_setfield(L, -2, "acreate");
1208 |
1209 | lua_pushcfunction(L, ngx_zookeeper_adelete);
1210 | lua_setfield(L, -2, "adelete");
1211 |
1212 | lua_pushcfunction(L, ngx_zookeeper_atree);
1213 | lua_setfield(L, -2, "atree");
1214 |
1215 | lua_pushcfunction(L, ngx_zookeeper_check_completition);
1216 | lua_setfield(L, -2, "check_completition");
1217 |
1218 | lua_pushcfunction(L, ngx_zookeeper_timeout);
1219 | lua_setfield(L, -2, "timeout");
1220 |
1221 | lua_pushcfunction(L, ngx_zookeeper_addrs);
1222 | lua_setfield(L, -2, "addrs");
1223 |
1224 | lua_pushcfunction(L, ngx_zookeeper_hostname);
1225 | lua_setfield(L, -2, "hostname");
1226 |
1227 | lua_pushcfunction(L, ngx_zookeeper_awatch);
1228 | lua_setfield(L, -2, "awatch");
1229 |
1230 | lua_pushcfunction(L, ngx_zookeeper_aunwatch);
1231 | lua_setfield(L, -2, "aunwatch");
1232 |
1233 | lua_pushcfunction(L, ngx_zookeeper_changed);
1234 | lua_setfield(L, -2, "changed");
1235 |
1236 | return 1;
1237 | }
1238 |
1239 |
1240 | static int
1241 | ngx_zookeeper_lua_error(lua_State *L, const char *where, const char *error)
1242 | {
1243 | char tmp[1024];
1244 |
1245 | snprintf(tmp, 1023, "%s: %s", where, error);
1246 |
1247 | lua_pushnil(L);
1248 | lua_pushlstring(L, tmp, strlen(tmp));
1249 |
1250 | return 2;
1251 | }
1252 |
1253 |
1254 | typedef struct
1255 | {
1256 | char *data;
1257 | ngx_uint_t len;
1258 | } str_t;
1259 |
1260 |
1261 | typedef void (*completition_t)(lua_State *L, void *p);
1262 |
1263 |
1264 | struct datatype_s
1265 | {
1266 | ngx_flag_t completed;
1267 | ngx_atomic_t ops;
1268 | completition_t completition_fn;
1269 |
1270 | struct Stat stat;
1271 | void *data;
1272 | const char *error;
1273 |
1274 | ngx_atomic_t lock;
1275 | volatile ngx_atomic_int_t refs;
1276 | ngx_pool_t *pool;
1277 | };
1278 | typedef struct datatype_s datatype_t;
1279 |
1280 | struct datatype_lua_s
1281 | {
1282 | datatype_t *inner;
1283 | };
1284 | typedef struct datatype_lua_s datatype_lua_t;
1285 |
1286 |
1287 | static void
1288 | dereference(datatype_t *data)
1289 | {
1290 | // ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "deref: 0x%p, refs=%l",
1291 | // data, data->refs);
1292 | if (1 == ngx_atomic_fetch_add(&data->refs, -1)) {
1293 | // ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "dealloc: 0x%p", data);
1294 | ngx_destroy_pool(data->pool);
1295 | }
1296 | }
1297 |
1298 |
1299 | static int
1300 | delete(lua_State *L)
1301 | {
1302 | datatype_lua_t *ud = luaL_checkudata(L, 1, "ngx_zoo");
1303 | // ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "lua delete: 0x%p",
1304 | // ud->inner);
1305 | dereference(ud->inner);
1306 | return 0;
1307 | }
1308 |
1309 |
1310 | static datatype_t *
1311 | new(lua_State *L)
1312 | {
1313 | datatype_lua_t *ud;
1314 | ngx_pool_t *pool;
1315 |
1316 | ud = (datatype_lua_t *) lua_newuserdata(L, sizeof(datatype_lua_t));
1317 | if (ud == NULL)
1318 | return NULL;
1319 |
1320 | pool = ngx_create_pool(2048, ngx_cycle->log);
1321 | if (pool == NULL)
1322 | return NULL;
1323 |
1324 | ud->inner = ngx_pcalloc(pool, sizeof(datatype_t));
1325 | if (ud->inner == NULL) {
1326 | ngx_destroy_pool(pool);
1327 | return NULL;
1328 | }
1329 |
1330 | ud->inner->refs = 2;
1331 | ud->inner->pool = pool;
1332 |
1333 | luaL_getmetatable(L, "ngx_zoo");
1334 | lua_setmetatable(L, -2);
1335 |
1336 | // ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "alloc: 0x%p", ud->inner);
1337 |
1338 | return ud->inner;
1339 | }
1340 |
1341 |
1342 | static int
1343 | ngx_zookeeper_connected(lua_State *L)
1344 | {
1345 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
1346 |
1347 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
1348 | ngx_zookeeper_lua_module);
1349 |
1350 | if (lua_gettop(L))
1351 | return ngx_zookeeper_lua_error(L, "connected", "no arguments expected");
1352 |
1353 | lua_pushboolean(L, zmcf->hosts.len != 0 /* not configured */ &&
1354 | (!zmcf->ev.timer_set /* suspended */ || (zmcf->zoo.handle && zmcf->zoo.connected != NGX_ERROR)));
1355 |
1356 | return 1;
1357 | }
1358 |
1359 |
1360 | static int
1361 | ngx_zookeeper_suspended(lua_State *L)
1362 | {
1363 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
1364 |
1365 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
1366 | ngx_zookeeper_lua_module);
1367 |
1368 | if (lua_gettop(L))
1369 | return ngx_zookeeper_lua_error(L, "suspended", "no arguments expected");
1370 |
1371 | lua_pushboolean(L, !zmcf->ev.timer_set);
1372 |
1373 | return 1;
1374 | }
1375 |
1376 |
1377 | static int
1378 | ngx_zookeeper_resume(lua_State *L)
1379 | {
1380 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
1381 |
1382 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
1383 | ngx_zookeeper_lua_module);
1384 |
1385 | if (lua_gettop(L))
1386 | return ngx_zookeeper_lua_error(L, "resume", "no arguments expected");
1387 |
1388 | if (!zmcf->ev.timer_set) {
1389 | zmcf->zoo.last_op = ngx_time();
1390 | ngx_zookeeper_monitor(&zmcf->ev);
1391 | }
1392 |
1393 | return 0;
1394 | }
1395 |
1396 |
1397 | static void
1398 | ngx_zookeeper_push_stat(lua_State *L, const struct Stat *stat)
1399 | {
1400 | lua_createtable(L, 0, 11);
1401 |
1402 | lua_pushliteral(L, "czxid");
1403 | lua_pushinteger(L, stat->czxid);
1404 | lua_rawset(L, -3);
1405 |
1406 | lua_pushliteral(L, "mzxid");
1407 | lua_pushinteger(L, stat->mzxid);
1408 | lua_rawset(L, -3);
1409 |
1410 | lua_pushliteral(L, "ctime");
1411 | lua_pushinteger(L, stat->ctime);
1412 | lua_rawset(L, -3);
1413 |
1414 | lua_pushliteral(L, "mtime");
1415 | lua_pushinteger(L, stat->mtime);
1416 | lua_rawset(L, -3);
1417 |
1418 | lua_pushliteral(L, "version");
1419 | lua_pushinteger(L, stat->version);
1420 | lua_rawset(L, -3);
1421 |
1422 | lua_pushliteral(L, "cversion");
1423 | lua_pushinteger(L, stat->cversion);
1424 | lua_rawset(L, -3);
1425 |
1426 | lua_pushliteral(L, "aversion");
1427 | lua_pushinteger(L, stat->aversion);
1428 | lua_rawset(L, -3);
1429 |
1430 | lua_pushliteral(L, "ephemeralOwner");
1431 | lua_pushinteger(L, stat->ephemeralOwner);
1432 | lua_rawset(L, -3);
1433 |
1434 | lua_pushliteral(L, "dataLength");
1435 | lua_pushinteger(L, stat->dataLength);
1436 | lua_rawset(L, -3);
1437 |
1438 | lua_pushliteral(L, "numChildren");
1439 | lua_pushinteger(L, stat->numChildren);
1440 | lua_rawset(L, -3);
1441 |
1442 | lua_pushliteral(L, "pzxid");
1443 | lua_pushinteger(L, stat->pzxid);
1444 | lua_rawset(L, -3);
1445 | }
1446 |
1447 |
1448 | static int
1449 | ngx_zookeeper_check_completition(lua_State *L)
1450 | {
1451 | datatype_lua_t *ud;
1452 | datatype_t *data;
1453 | zookeeper_t *zoo = ngx_http_zmcf();
1454 | int n = 3;
1455 |
1456 | zoo->last_op = ngx_time();
1457 |
1458 | if (lua_gettop(L) != 1)
1459 | return ngx_zookeeper_lua_error(L, "check_completition",
1460 | "exactly one arguments expected");
1461 |
1462 | if (!lua_isuserdata(L, 1))
1463 | return ngx_zookeeper_lua_error(L, "check_completition",
1464 | "argument must be a userdata");
1465 |
1466 | ud = (datatype_lua_t *) luaL_checkudata(L, 1, "ngx_zoo");
1467 | if (ud == NULL)
1468 | return ngx_zookeeper_lua_error(L, "check_completition",
1469 | "argument is not a zookeeper type");
1470 |
1471 | data = ud->inner;
1472 |
1473 | ngx_rwlock_wlock(&data->lock);
1474 |
1475 | if (zoo->handle == NULL) {
1476 |
1477 | ngx_rwlock_unlock(&data->lock);
1478 |
1479 | return ngx_zookeeper_lua_error(L, "check_completition",
1480 | "zookeeper handle is nil");
1481 | }
1482 |
1483 | if (zoo->connected == NGX_ERROR) {
1484 |
1485 | ngx_rwlock_unlock(&data->lock);
1486 |
1487 | return ngx_zookeeper_lua_error(L, "check_completition",
1488 | "not connected");
1489 | }
1490 |
1491 | lua_pushboolean(L, data->completed);
1492 |
1493 | if (!data->completed) {
1494 |
1495 | ngx_rwlock_unlock(&data->lock);
1496 | return 1;
1497 | }
1498 |
1499 | if (data->error == NULL) {
1500 |
1501 | if (data->data != NULL) {
1502 |
1503 | data->completition_fn(L, data->data);
1504 | lua_pushnil(L);
1505 |
1506 | } else {
1507 |
1508 | lua_pushnil(L);
1509 | lua_pushnil(L);
1510 | }
1511 |
1512 | if (data->stat.pzxid) {
1513 |
1514 | ngx_zookeeper_push_stat(L, &data->stat);
1515 | n++;
1516 | }
1517 |
1518 | goto done;
1519 | }
1520 |
1521 | lua_pushnil(L);
1522 | lua_pushlstring(L, data->error, strlen(data->error));
1523 |
1524 | done:
1525 |
1526 | return n;
1527 | }
1528 |
1529 |
1530 | static int
1531 | ngx_zookeeper_timeout(lua_State *L)
1532 | {
1533 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
1534 |
1535 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
1536 | ngx_zookeeper_lua_module);
1537 |
1538 | lua_pushinteger(L, zmcf->recv_timeout);
1539 |
1540 | return 1;
1541 | }
1542 |
1543 |
1544 | static int
1545 | ngx_zookeeper_addrs(lua_State *L)
1546 | {
1547 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
1548 | ngx_uint_t j;
1549 |
1550 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
1551 | ngx_zookeeper_lua_module);
1552 |
1553 | lua_newtable(L);
1554 |
1555 | for (j = 0; j < zmcf->naddrs; j++) {
1556 |
1557 | lua_pushlstring(L, (const char *) zmcf->addrs[j].name.data,
1558 | zmcf->addrs[j].name.len);
1559 | lua_rawseti(L, -2, j + 1);
1560 | }
1561 |
1562 | return 1;
1563 | }
1564 |
1565 |
1566 | static int
1567 | ngx_zookeeper_hostname(lua_State *L)
1568 | {
1569 | lua_pushlstring(L, (const char *) ngx_cycle->hostname.data,
1570 | ngx_cycle->hostname.len);
1571 | return 1;
1572 | }
1573 |
1574 |
1575 | //------------------------------------------------------------------------------
1576 |
1577 |
1578 | static void
1579 | ngx_zookeeper_string_completition(lua_State *L, void *p)
1580 | {
1581 | str_t *s = p;
1582 | return lua_pushlstring(L, s->data, s->len);
1583 | }
1584 |
1585 |
1586 | static void
1587 | ngx_zookeeper_string_ready(int rc, const char *value, int value_len,
1588 | const struct Stat *stat, const void *p)
1589 | {
1590 | datatype_t *data = (datatype_t *) p;
1591 | str_t *s;
1592 |
1593 | if (data == NULL)
1594 | return;
1595 |
1596 | ngx_rwlock_wlock(&data->lock);
1597 |
1598 | if (data->refs == 1)
1599 | goto end;
1600 |
1601 | if (rc != ZOK) {
1602 |
1603 | data->error = ngx_zerr(rc);
1604 | goto end;
1605 | }
1606 |
1607 | s = ngx_pcalloc(data->pool, sizeof(str_t));
1608 | if (s == NULL)
1609 | goto nomem;
1610 |
1611 | if (value != NULL && value_len != 0) {
1612 |
1613 | s->data = ngx_pcalloc(data->pool, value_len);
1614 | if (s->data == NULL)
1615 | goto nomem;
1616 |
1617 | ngx_memcpy(s->data, value, value_len);
1618 | s->len = value_len;
1619 | } else {
1620 |
1621 | s->data = "";
1622 | s->len = 0;
1623 | }
1624 |
1625 | data->data = s;
1626 |
1627 | if (stat)
1628 | ngx_memcpy(&data->stat, stat, sizeof(struct Stat));
1629 |
1630 | goto end;
1631 |
1632 | nomem:
1633 |
1634 | data->error = "no memory";
1635 |
1636 | end:
1637 |
1638 | data->completed = 1;
1639 |
1640 | ngx_rwlock_unlock(&data->lock);
1641 |
1642 | dereference(data);
1643 | }
1644 |
1645 |
1646 | static void
1647 | ngx_zookeeper_void_completition(lua_State *L, void *p)
1648 | {}
1649 |
1650 |
1651 | static void
1652 | ngx_zookeeper_void_ready(int rc, const void *p)
1653 | {
1654 | datatype_t *data = (datatype_t *) p;
1655 |
1656 | if (data == NULL)
1657 | return;
1658 |
1659 | if (data->refs == 1)
1660 | goto end;
1661 |
1662 | ngx_rwlock_wlock(&data->lock);
1663 |
1664 | if (rc != ZOK)
1665 | data->error = ngx_zerr(rc);
1666 |
1667 | data->completed = 1;
1668 |
1669 | ngx_rwlock_unlock(&data->lock);
1670 |
1671 | end:
1672 |
1673 | dereference(data);
1674 | }
1675 |
1676 | //------------------------------------------------------------------------------
1677 |
1678 | static void
1679 | ngx_zookeeper_get_completition(lua_State *L, void *p)
1680 | {
1681 | ngx_zookeeper_string_completition(L, p);
1682 | }
1683 |
1684 |
1685 | static void
1686 | ngx_zookeeper_get_ready(int rc, const char *value, int value_len,
1687 | const struct Stat *stat, const void *p)
1688 | {
1689 | ngx_zookeeper_string_ready(rc, value, value_len, stat, p);
1690 | }
1691 |
1692 |
1693 | static int
1694 | ngx_zookeeper_aget(lua_State *L)
1695 | {
1696 | int rc;
1697 | datatype_t *data;
1698 | str_t path;
1699 | zookeeper_t *zoo;
1700 |
1701 | ngx_http_zookeeper_check_mon();
1702 |
1703 | zoo = ngx_http_zmcf();
1704 |
1705 | if (zoo->handle == NULL)
1706 | return ngx_zookeeper_lua_error(L, "aget", "zookeeper handle is nil");
1707 |
1708 | if (zoo->connected == NGX_ERROR)
1709 | return ngx_zookeeper_lua_error(L, "aget", "not connected");
1710 |
1711 | if (lua_gettop(L) != 1)
1712 | return ngx_zookeeper_lua_error(L, "aget",
1713 | "exactly one arguments expected");
1714 |
1715 | data = new(L);
1716 | if (data == NULL)
1717 | return ngx_zookeeper_lua_error(L, "aget", "no memory");
1718 |
1719 | path.data = (char *) luaL_checklstring(L, 1, &path.len);
1720 | data->completition_fn = ngx_zookeeper_get_completition;
1721 |
1722 | rc = zoo_aget(zoo->handle, path.data, 0,
1723 | ngx_zookeeper_get_ready, data);
1724 | if (rc == ZOK)
1725 | return 1;
1726 |
1727 | dereference(data);
1728 |
1729 | /* pop userdata */
1730 | lua_pop(L, 1);
1731 |
1732 | return ngx_zookeeper_lua_error(L, "aget", ngx_zerr(rc));
1733 | }
1734 |
1735 |
1736 | //------------------------------------------------------------------------------
1737 |
1738 | static void
1739 | ngx_zookeeper_get_childrens_completition(lua_State *L, void *p)
1740 | {
1741 | ngx_array_t *data = p;
1742 | str_t *s;
1743 | ngx_uint_t j;
1744 |
1745 | lua_createtable(L, data->nelts, 0);
1746 |
1747 | s = data->elts;
1748 |
1749 | for (j = 0; j < data->nelts; j++) {
1750 |
1751 | lua_pushlstring(L, s[j].data, s[j].len);
1752 | lua_rawseti(L, -2, j + 1);
1753 | }
1754 | }
1755 |
1756 |
1757 | static void
1758 | ngx_zookeeper_get_childrens_ready(int rc, const struct String_vector *strings,
1759 | const void *p)
1760 | {
1761 | datatype_t *data = (datatype_t *) p;
1762 | ngx_array_t *arr;
1763 | str_t *s;
1764 | ngx_int_t j;
1765 |
1766 | if (data == NULL)
1767 | return;
1768 |
1769 | ngx_rwlock_wlock(&data->lock);
1770 |
1771 | if (data->refs == 1)
1772 | goto end;
1773 |
1774 | if (rc != ZOK) {
1775 |
1776 | data->error = ngx_zerr(rc);
1777 | goto end;
1778 | }
1779 |
1780 | arr = ngx_array_create(data->pool, strings->count, sizeof(str_t));
1781 | if (arr == NULL)
1782 | goto nomem;
1783 |
1784 | if (strings != NULL && strings->data != NULL && strings->count != 0) {
1785 |
1786 | for (j = 0; j < strings->count; j++) {
1787 |
1788 | s = ngx_array_push(arr);
1789 | if (s == NULL)
1790 | goto nomem;
1791 |
1792 | s->len = strlen(strings->data[j]);
1793 | s->data = ngx_pcalloc(data->pool, s->len);
1794 |
1795 | ngx_memcpy(s->data, strings->data[j], s->len);
1796 | }
1797 | }
1798 |
1799 | data->data = arr;
1800 |
1801 | goto end;
1802 |
1803 | nomem:
1804 |
1805 | data->error = "no memory";
1806 |
1807 | end:
1808 |
1809 | data->completed = 1;
1810 |
1811 | ngx_rwlock_unlock(&data->lock);
1812 |
1813 | dereference(data);
1814 | }
1815 |
1816 |
1817 | static int
1818 | ngx_zookeeper_aget_childrens(lua_State *L)
1819 | {
1820 | int rc;
1821 | datatype_t *data;
1822 | str_t path;
1823 | zookeeper_t *zoo;
1824 |
1825 | ngx_http_zookeeper_check_mon();
1826 |
1827 | zoo = ngx_http_zmcf();
1828 |
1829 | if (zoo->handle == NULL)
1830 | return ngx_zookeeper_lua_error(L, "aget_childrens",
1831 | "zookeeper handle is nil");
1832 |
1833 | if (zoo->connected == NGX_ERROR)
1834 | return ngx_zookeeper_lua_error(L, "aget_childrens", "not connected");
1835 |
1836 | if (lua_gettop(L) != 1)
1837 | return ngx_zookeeper_lua_error(L, "aget_childrens",
1838 | "exactly one arguments expected");
1839 |
1840 | data = new(L);
1841 | if (data == NULL)
1842 | return ngx_zookeeper_lua_error(L, "aget_childrens", "no memory");
1843 |
1844 | path.data = (char *) luaL_checklstring(L, 1, &path.len);
1845 | data->completition_fn = ngx_zookeeper_get_childrens_completition;
1846 |
1847 | rc = zoo_aget_children(zoo->handle, path.data, 0,
1848 | ngx_zookeeper_get_childrens_ready, data);
1849 | if (rc == ZOK)
1850 | return 1;
1851 |
1852 | dereference(data);
1853 |
1854 | /* pop userdata */
1855 | lua_pop(L, 1);
1856 |
1857 | return ngx_zookeeper_lua_error(L, "aget_childrens", ngx_zerr(rc));
1858 | }
1859 |
1860 |
1861 | //------------------------------------------------------------------------------
1862 |
1863 |
1864 | static void
1865 | ngx_zookeeper_set_completition(lua_State *L, void *p)
1866 | {
1867 | ngx_zookeeper_void_completition(L, p);
1868 | }
1869 |
1870 |
1871 | static void
1872 | ngx_zookeeper_set_ready(int rc, const struct Stat *stat, const void *p)
1873 | {
1874 | datatype_t *data = (datatype_t *) p;
1875 |
1876 | if (data == NULL)
1877 | return;
1878 |
1879 | if (data->refs == 1)
1880 | goto end;
1881 |
1882 | ngx_rwlock_wlock(&data->lock);
1883 |
1884 | if (rc == ZOK) {
1885 |
1886 | if (stat)
1887 | ngx_memcpy(&data->stat, stat, sizeof(struct Stat));
1888 |
1889 | } else
1890 | data->error = ngx_zerr(rc);
1891 |
1892 | data->completed = 1;
1893 |
1894 | ngx_rwlock_unlock(&data->lock);
1895 |
1896 | end:
1897 |
1898 | dereference(data);
1899 | }
1900 |
1901 |
1902 | static int
1903 | ngx_zookeeper_aset(lua_State *L)
1904 | {
1905 | int rc;
1906 | lua_Integer version = -1;
1907 | str_t value;
1908 | datatype_t *data;
1909 | str_t path;
1910 | zookeeper_t *zoo;
1911 |
1912 | ngx_http_zookeeper_check_mon();
1913 |
1914 | zoo = ngx_http_zmcf();
1915 |
1916 | if (zoo->handle == NULL)
1917 | return ngx_zookeeper_lua_error(L, "aset", "zookeeper handle is nil");
1918 |
1919 | if (zoo->connected == NGX_ERROR)
1920 | return ngx_zookeeper_lua_error(L, "aset", "not connected");
1921 |
1922 | rc = lua_gettop(L);
1923 |
1924 | if (rc != 2 && rc != 3)
1925 | return ngx_zookeeper_lua_error(L, "aset",
1926 | "exactly 2 or 3 arguments expected");
1927 |
1928 | data = new(L);
1929 | if (data == NULL)
1930 | return ngx_zookeeper_lua_error(L, "aset", "no memory");
1931 |
1932 | path.data = (char *) luaL_checklstring(L, 1, &path.len);
1933 | value.data = (char *) luaL_checklstring(L, 2, &value.len);
1934 |
1935 | if (rc == 3)
1936 | version = luaL_checkinteger(L, 3);
1937 |
1938 | data->completition_fn = ngx_zookeeper_set_completition;
1939 |
1940 | rc = zoo_aset(zoo->handle, path.data, value.data, value.len, version,
1941 | ngx_zookeeper_set_ready, data);
1942 | if (rc == ZOK) {
1943 | return 1;
1944 | }
1945 |
1946 | dereference(data);
1947 |
1948 | /* pop userdata */
1949 | lua_pop(L, 1);
1950 |
1951 | return ngx_zookeeper_lua_error(L, "aset", ngx_zerr(rc));
1952 | }
1953 |
1954 |
1955 | //------------------------------------------------------------------------------
1956 |
1957 |
1958 | static void
1959 | ngx_zookeeper_create_completition(lua_State *L, void *p)
1960 | {
1961 | ngx_zookeeper_string_completition(L, p);
1962 | }
1963 |
1964 |
1965 | static void
1966 | ngx_zookeeper_create_ready(int rc, const char *value, const void *p)
1967 | {
1968 | ngx_zookeeper_string_ready(rc, value, value ? strlen(value) : 0, NULL, p);
1969 | }
1970 |
1971 |
1972 | static int
1973 | ngx_zookeeper_acreate(lua_State *L)
1974 | {
1975 | int rc, flags = 0;
1976 | str_t value;
1977 | datatype_t *data;
1978 | str_t path;
1979 | zookeeper_t *zoo;
1980 |
1981 | ngx_http_zookeeper_check_mon();
1982 |
1983 | zoo = ngx_http_zmcf();
1984 |
1985 | if (zoo->handle == NULL)
1986 | return ngx_zookeeper_lua_error(L, "acreate", "zookeeper handle is nil");
1987 |
1988 | if (zoo->connected == NGX_ERROR)
1989 | return ngx_zookeeper_lua_error(L, "acreate", "not connected");
1990 |
1991 | if (lua_gettop(L) != 2 && lua_gettop(L) != 3)
1992 | return ngx_zookeeper_lua_error(L, "acreate",
1993 | "exactly 2 or 3 arguments expected");
1994 |
1995 | if (lua_gettop(L) == 3)
1996 | flags = luaL_checkinteger(L, 3);
1997 |
1998 | data = new(L);
1999 | if (data == NULL)
2000 | return ngx_zookeeper_lua_error(L, "acreate", "no memory");
2001 |
2002 | path.data = (char *) luaL_checklstring(L, 1, &path.len);
2003 | value.data = (char *) luaL_checklstring(L, 2, &value.len);
2004 |
2005 | data->completition_fn = ngx_zookeeper_create_completition;
2006 |
2007 | rc = zoo_acreate(zoo->handle, path.data, value.data, value.len,
2008 | &ZOO_OPEN_ACL_UNSAFE, flags, ngx_zookeeper_create_ready, data);
2009 | if (rc == ZOK)
2010 | return 1;
2011 |
2012 | dereference(data);
2013 |
2014 | /* pop userdata */
2015 | lua_pop(L, 1);
2016 |
2017 | return ngx_zookeeper_lua_error(L, "acreate", ngx_zerr(rc));
2018 | }
2019 |
2020 |
2021 | //------------------------------------------------------------------------------
2022 |
2023 |
2024 | static void
2025 | ngx_zookeeper_delete_completition(lua_State *L, void *p)
2026 | {
2027 | ngx_zookeeper_void_completition(L, p);
2028 | }
2029 |
2030 |
2031 | static void
2032 | ngx_zookeeper_delete_ready(int rc, const void *p)
2033 | {
2034 | return ngx_zookeeper_void_ready(rc, p);
2035 | }
2036 |
2037 |
2038 | static int
2039 | ngx_zookeeper_adelete(lua_State *L)
2040 | {
2041 | int rc;
2042 | datatype_t *data;
2043 | str_t path;
2044 | zookeeper_t *zoo;
2045 |
2046 | ngx_http_zookeeper_check_mon();
2047 |
2048 | zoo = ngx_http_zmcf();
2049 |
2050 | if (zoo->handle == NULL)
2051 | return ngx_zookeeper_lua_error(L, "adelete", "zookeeper handle is nil");
2052 |
2053 | if (zoo->connected == NGX_ERROR)
2054 | return ngx_zookeeper_lua_error(L, "adelete", "not connected");
2055 |
2056 | if (lua_gettop(L) != 1)
2057 | return ngx_zookeeper_lua_error(L, "adelete",
2058 | "exactly one arguments expected");
2059 |
2060 | data = new(L);
2061 | if (data == NULL)
2062 | return ngx_zookeeper_lua_error(L, "adelete", "no memory");
2063 |
2064 | path.data = (char *) luaL_checklstring(L, 1, &path.len);
2065 |
2066 | data->completition_fn = ngx_zookeeper_delete_completition;
2067 |
2068 | rc = zoo_adelete(zoo->handle, path.data, -1,
2069 | ngx_zookeeper_delete_ready, data);
2070 | if (rc == ZOK)
2071 | return 1;
2072 |
2073 | dereference(data);
2074 |
2075 | /* pop userdata */
2076 | lua_pop(L, 1);
2077 |
2078 | return ngx_zookeeper_lua_error(L, "adelete", ngx_zerr(rc));
2079 | }
2080 |
2081 |
2082 | //------------------------------------------------------------------------------
2083 |
2084 |
2085 | struct ngx_zoo_tree_node_s {
2086 | datatype_t *data;
2087 | ngx_array_t *childrens;
2088 | str_t value;
2089 | str_t name;
2090 | str_t path;
2091 | struct Stat stat;
2092 | };
2093 | typedef struct ngx_zoo_tree_node_s ngx_zoo_tree_node_t;
2094 |
2095 |
2096 | static void
2097 | ngx_zookeeper_tree_push(lua_State *L, ngx_zoo_tree_node_t *node)
2098 | {
2099 | ngx_zoo_tree_node_t *childrens;
2100 | ngx_uint_t j;
2101 |
2102 | lua_newtable(L);
2103 |
2104 | lua_pushlstring(L, node->value.data, node->value.len);
2105 | lua_setfield(L, -2, "__value");
2106 |
2107 | ngx_zookeeper_push_stat(L, &node->stat);
2108 | lua_setfield(L, -2, "__stat");
2109 |
2110 | if (node->childrens == NULL)
2111 | return;
2112 |
2113 | childrens = node->childrens->elts;
2114 |
2115 | for (j = 0; j < node->childrens->nelts; j++) {
2116 |
2117 | lua_pushlstring(L, childrens[j].name.data, childrens[j].name.len);
2118 | ngx_zookeeper_tree_push(L, childrens + j);
2119 | lua_rawset(L, -3);
2120 | }
2121 | }
2122 |
2123 |
2124 | static void
2125 | ngx_zookeeper_tree_completition(lua_State *L, void *p)
2126 | {
2127 | ngx_zoo_tree_node_t *node = (ngx_zoo_tree_node_t *) p;
2128 | ngx_zookeeper_tree_push(L, node);
2129 | }
2130 |
2131 |
2132 | static void
2133 | ngx_zookeeper_tree_get_ready(int rc, const char *value, int value_len,
2134 | const struct Stat *stat, const void *p);
2135 |
2136 |
2137 | static void
2138 | ngx_zookeeper_tree_childrens_ready(int rc, const struct String_vector *strings,
2139 | const void *p)
2140 | {
2141 | ngx_zoo_tree_node_t *parent = (ngx_zoo_tree_node_t *) p;
2142 | ngx_zoo_tree_node_t *node;
2143 | ngx_int_t j;
2144 | datatype_t *data;
2145 | zookeeper_t *zoo;
2146 |
2147 | zoo = ngx_http_zmcf();
2148 |
2149 | data = parent->data;
2150 |
2151 | ngx_rwlock_wlock(&data->lock);
2152 |
2153 | if (data->refs == 1)
2154 | goto end;
2155 |
2156 | if (rc != ZOK)
2157 | goto err;
2158 |
2159 | parent->childrens = ngx_array_create(data->pool,
2160 | strings->count, sizeof(ngx_zoo_tree_node_t));
2161 | if (parent->childrens == NULL)
2162 | goto nomem;
2163 |
2164 | for (j = 0; j < strings->count; j++) {
2165 |
2166 | node = ngx_array_push(parent->childrens);
2167 | if (node == NULL)
2168 | goto nomem;
2169 |
2170 | ngx_memzero(node, sizeof(ngx_zoo_tree_node_t));
2171 | node->data = parent->data;
2172 |
2173 | // node name
2174 | node->name.len = strlen(strings->data[j]);
2175 | node->name.data = ngx_pcalloc(data->pool, node->name.len + 1);
2176 | if (node->name.data == NULL)
2177 | goto nomem;
2178 | ngx_memcpy(node->name.data, strings->data[j], node->name.len);
2179 |
2180 | // node zpath
2181 | node->path.len = parent->path.len + 1 + node->name.len;
2182 | node->path.data = ngx_pcalloc(data->pool, node->path.len + 1);
2183 | if (node->path.data == NULL)
2184 | goto nomem;
2185 | ngx_memcpy(node->path.data, parent->path.data, parent->path.len);
2186 | node->path.data[parent->path.len] = '/';
2187 | ngx_memcpy(node->path.data + parent->path.len + 1, node->name.data,
2188 | node->name.len);
2189 |
2190 | ngx_atomic_fetch_add(&data->ops, 1);
2191 |
2192 | rc = zoo_aget(zoo->handle, node->path.data, 0,
2193 | ngx_zookeeper_tree_get_ready, node);
2194 | if (rc != ZOK) {
2195 | ngx_atomic_fetch_add(&data->ops, -1);
2196 | goto err;
2197 | }
2198 | }
2199 |
2200 | goto end;
2201 |
2202 | err:
2203 |
2204 | data->error = ngx_zerr(rc);
2205 |
2206 | goto end;
2207 |
2208 | nomem:
2209 |
2210 | data->error = "no memory";
2211 |
2212 | end:
2213 |
2214 | data->completed = ngx_atomic_fetch_add(&data->ops, -1) == 1;
2215 |
2216 | ngx_rwlock_unlock(&data->lock);
2217 |
2218 | if (data->completed)
2219 | dereference(data);
2220 | }
2221 |
2222 |
2223 | static void
2224 | ngx_zookeeper_tree_get_ready(int rc, const char *value, int value_len,
2225 | const struct Stat *stat, const void *p)
2226 | {
2227 | ngx_zoo_tree_node_t *node = (ngx_zoo_tree_node_t *) p;
2228 | datatype_t *data;
2229 | zookeeper_t *zoo;
2230 |
2231 | zoo = ngx_http_zmcf();
2232 |
2233 | data = node->data;
2234 |
2235 | ngx_rwlock_wlock(&data->lock);
2236 |
2237 | if (data->refs == 1)
2238 | goto end;
2239 |
2240 | if (rc != ZOK)
2241 | goto err;
2242 |
2243 | if (value != NULL && value_len != 0) {
2244 |
2245 | node->value.data = ngx_pcalloc(data->pool, value_len);
2246 | if (node->value.data == NULL)
2247 | goto nomem;
2248 |
2249 | ngx_memcpy(node->value.data, value, value_len);
2250 | node->value.len = value_len;
2251 | } else {
2252 |
2253 | node->value.data = "";
2254 | }
2255 |
2256 | ngx_memcpy(&node->stat, stat, sizeof(struct Stat));
2257 |
2258 | if (stat->numChildren == 0)
2259 | goto end;
2260 |
2261 | ngx_atomic_fetch_add(&data->ops, 1);
2262 |
2263 | if (node->path.data[node->path.len - 1] == '/')
2264 | node->path.len--;
2265 |
2266 | rc = zoo_aget_children(zoo->handle, node->path.data, 0,
2267 | ngx_zookeeper_tree_childrens_ready, node);
2268 | if (rc != ZOK) {
2269 | ngx_atomic_fetch_add(&data->ops, -1);
2270 | goto err;
2271 | }
2272 |
2273 | goto end;
2274 |
2275 | err:
2276 |
2277 | data->error = ngx_zerr(rc);
2278 |
2279 | goto end;
2280 |
2281 | nomem:
2282 |
2283 | data->error = "no memory";
2284 |
2285 | end:
2286 |
2287 | data->completed = ngx_atomic_fetch_add(&data->ops, -1) == 1;
2288 |
2289 | ngx_rwlock_unlock(&data->lock);
2290 |
2291 | if (data->completed)
2292 | dereference(data);
2293 | }
2294 |
2295 |
2296 | static int
2297 | ngx_zookeeper_atree(lua_State *L)
2298 | {
2299 | int rc;
2300 | datatype_t *data;
2301 | str_t path;
2302 | ngx_zoo_tree_node_t *node;
2303 | zookeeper_t *zoo;
2304 |
2305 | ngx_http_zookeeper_check_mon();
2306 |
2307 | zoo = ngx_http_zmcf();
2308 |
2309 | if (zoo->handle == NULL)
2310 | return ngx_zookeeper_lua_error(L, "atree",
2311 | "zookeeper handle is nil");
2312 |
2313 | if (zoo->connected == NGX_ERROR)
2314 | return ngx_zookeeper_lua_error(L, "atree", "not connected");
2315 |
2316 | if (lua_gettop(L) != 1)
2317 | return ngx_zookeeper_lua_error(L, "atree",
2318 | "exactly one arguments expected");
2319 |
2320 | data = new(L);
2321 | if (data == NULL)
2322 | return ngx_zookeeper_lua_error(L, "atree", "no memory");
2323 |
2324 | node = ngx_pcalloc(data->pool, sizeof(ngx_zoo_tree_node_t));
2325 | if (node == NULL)
2326 | return ngx_zookeeper_lua_error(L, "atree", "no memory");
2327 |
2328 | path.data = (char *) luaL_checklstring(L, 1, &path.len);
2329 |
2330 | node->path.data = ngx_pcalloc(data->pool, path.len + 1);
2331 | if (node->path.data == NULL)
2332 | return ngx_zookeeper_lua_error(L, "atree", "no memory");
2333 |
2334 | ngx_memcpy(node->path.data, path.data, path.len);
2335 | node->path.len = path.len;
2336 |
2337 | node->data = data;
2338 | data->completition_fn = ngx_zookeeper_tree_completition;
2339 | data->ops = 1;
2340 | data->data = node;
2341 |
2342 | rc = zoo_aget(zoo->handle, node->path.data, 0,
2343 | ngx_zookeeper_tree_get_ready, node);
2344 | if (rc == ZOK)
2345 | return 1;
2346 |
2347 | dereference(data);
2348 |
2349 | /* pop userdata */
2350 | lua_pop(L, 1);
2351 |
2352 | return ngx_zookeeper_lua_error(L, "atree", ngx_zerr(rc));
2353 | }
2354 |
2355 |
2356 | typedef struct {
2357 | datatype_t *data;
2358 | ngx_int_t index;
2359 | } watch_ready_context_t;
2360 |
2361 |
2362 | static void
2363 | ngx_zookeeper_watch(zhandle_t *zh, int type,
2364 | int state, const char *path, void *ctxp)
2365 | {
2366 | ngx_int_t index = (ngx_int_t) ctxp;
2367 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
2368 | watched_t *w;
2369 |
2370 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
2371 | ngx_zookeeper_lua_module);
2372 |
2373 | if (type == ZOO_CHILD_EVENT
2374 | || type == ZOO_CHANGED_EVENT
2375 | || type == ZOO_DELETED_EVENT) {
2376 |
2377 | ngx_rwlock_wlock(&zmcf->lock);
2378 |
2379 | w = ((watched_t *) zmcf->watched->elts) + index;
2380 | if (w->path.data && w->watch_type == type && ngx_strncmp(path, w->path.data, w->path.len) == 0)
2381 | w->changed = 1;
2382 |
2383 | ngx_rwlock_unlock(&zmcf->lock);
2384 | }
2385 | }
2386 |
2387 |
2388 | static void
2389 | ngx_zookeeper_awatch_free_slot(watched_t *w)
2390 | {
2391 | ngx_free(w->path.data);
2392 | ngx_str_null(&w->path);
2393 | w->changed = 0;
2394 | w->watch_type = 0;
2395 | }
2396 |
2397 |
2398 | static void
2399 | ngx_zookeeper_watch_ready(int rc, watch_ready_context_t *ctx)
2400 | {
2401 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
2402 | watched_t *w;
2403 |
2404 | if (rc == ZOK)
2405 | return;
2406 |
2407 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
2408 | ngx_zookeeper_lua_module);
2409 |
2410 | ngx_rwlock_wlock(&zmcf->lock);
2411 |
2412 | w = zmcf->watched->elts;
2413 |
2414 | ngx_zookeeper_awatch_free_slot(w + ctx->index);
2415 |
2416 | ngx_rwlock_unlock(&zmcf->lock);
2417 | }
2418 |
2419 |
2420 | static void
2421 | ngx_zookeeper_watch_data_ready(int rc, const char *value, int value_len,
2422 | const struct Stat *stat, const void *ctxp)
2423 | {
2424 | watch_ready_context_t *ctx = (watch_ready_context_t *) ctxp;
2425 |
2426 | ngx_zookeeper_watch_ready(rc, ctx);
2427 |
2428 | return ngx_zookeeper_get_ready(rc, value, value_len, stat, ctx->data);
2429 | }
2430 |
2431 |
2432 | static void
2433 | ngx_zookeeper_watch_children_ready(int rc, const struct String_vector *strings,
2434 | const void *ctxp)
2435 | {
2436 | watch_ready_context_t *ctx = (watch_ready_context_t *) ctxp;
2437 |
2438 | ngx_zookeeper_watch_ready(rc, ctx);
2439 |
2440 | return ngx_zookeeper_get_childrens_ready(rc, strings, ctx->data);
2441 | }
2442 |
2443 |
2444 | static ngx_int_t
2445 | ngx_zookeeper_awatch_exists(str_t path, int watch_type)
2446 | {
2447 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
2448 | watched_t *w;
2449 | ngx_uint_t j;
2450 | ngx_str_t s = { path.len, (u_char *) path.data };
2451 |
2452 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
2453 | ngx_zookeeper_lua_module);
2454 |
2455 | w = zmcf->watched->elts;
2456 |
2457 | for (j = 0; j < zmcf->watched->nelts; j++)
2458 | if (str_eq(s, w[j].path) && w[j].watch_type == watch_type)
2459 | return j;
2460 |
2461 | return NGX_DECLINED;
2462 | }
2463 |
2464 |
2465 | static ngx_int_t
2466 | ngx_zookeeper_awatch_slot()
2467 | {
2468 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
2469 | watched_t *w;
2470 | ngx_uint_t j;
2471 |
2472 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
2473 | ngx_zookeeper_lua_module);
2474 |
2475 | w = zmcf->watched->elts;
2476 |
2477 | for (j = 0; j < zmcf->watched->nelts; j++)
2478 | if (w[j].path.data == NULL)
2479 | return j;
2480 |
2481 | w = ngx_array_push(zmcf->watched);
2482 | if (w != NULL)
2483 | return zmcf->watched->nelts - 1;
2484 |
2485 | return NGX_ERROR;
2486 | }
2487 |
2488 |
2489 | static int
2490 | ngx_zookeeper_awatch(lua_State *L)
2491 | {
2492 | int rc;
2493 | datatype_t *data = NULL;
2494 | str_t path;
2495 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
2496 | watched_t *w;
2497 | watch_ready_context_t *ctx;
2498 | int watch_type;
2499 |
2500 | ngx_http_zookeeper_check_mon();
2501 |
2502 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
2503 | ngx_zookeeper_lua_module);
2504 |
2505 | if (zmcf->zoo.handle == NULL)
2506 | return ngx_zookeeper_lua_error(L, "awatch", "zookeeper handle is nil");
2507 |
2508 | if (zmcf->zoo.connected == NGX_ERROR)
2509 | return ngx_zookeeper_lua_error(L, "awatch", "not connected");
2510 |
2511 | if (lua_gettop(L) != 2)
2512 | return ngx_zookeeper_lua_error(L, "awatch", "2 arguments expected");
2513 |
2514 | watch_type = luaL_checkinteger(L, 2);
2515 |
2516 | if (watch_type != ZOO_CHILD_EVENT && watch_type != ZOO_CHANGED_EVENT)
2517 | return ngx_zookeeper_lua_error(L, "awatch", "invalid watch type");
2518 |
2519 | ngx_rwlock_wlock(&zmcf->lock);
2520 |
2521 | path.data = (char *) luaL_checklstring(L, 1, &path.len);
2522 |
2523 | if (ngx_zookeeper_awatch_exists(path, watch_type) != NGX_DECLINED) {
2524 |
2525 | ngx_rwlock_unlock(&zmcf->lock);
2526 | return ngx_zookeeper_lua_error(L, "awatch", "exists");
2527 | }
2528 |
2529 | data = new(L);
2530 | if (data == NULL)
2531 | goto nomem;
2532 |
2533 | ctx = ngx_pcalloc(data->pool, sizeof(watch_ready_context_t));
2534 | if (ctx == NULL)
2535 | goto nomem;
2536 |
2537 | ctx->index = ngx_zookeeper_awatch_slot();
2538 | if (ctx->index == NGX_ERROR)
2539 | goto nomem;
2540 |
2541 | w = ((watched_t *) zmcf->watched->elts) + ctx->index;
2542 |
2543 | ctx->data = data;
2544 |
2545 | w->path.len = path.len;
2546 | w->path.data = ngx_calloc(path.len + 1, ngx_cycle->log);
2547 | if (w->path.data == NULL)
2548 | goto nomem;
2549 | ngx_memcpy(w->path.data, path.data, path.len);
2550 | w->watch_type = watch_type;
2551 | w->changed = 0;
2552 |
2553 | if (watch_type == ZOO_CHANGED_EVENT) {
2554 |
2555 | data->completition_fn = ngx_zookeeper_get_completition;
2556 | rc = zoo_awget(zmcf->zoo.handle, path.data,
2557 | ngx_zookeeper_watch, (void *) ctx->index,
2558 | ngx_zookeeper_watch_data_ready, ctx);
2559 |
2560 | } else {
2561 |
2562 | data->completition_fn = ngx_zookeeper_get_childrens_completition;
2563 | rc = zoo_awget_children(zmcf->zoo.handle, path.data,
2564 | ngx_zookeeper_watch, (void *) ctx->index,
2565 | ngx_zookeeper_watch_children_ready, ctx);
2566 |
2567 | }
2568 |
2569 | if (rc == ZOK) {
2570 |
2571 | ngx_rwlock_unlock(&zmcf->lock);
2572 | return 1;
2573 | }
2574 |
2575 | ngx_zookeeper_awatch_free_slot(w);
2576 |
2577 | ngx_rwlock_unlock(&zmcf->lock);
2578 |
2579 | dereference(data);
2580 |
2581 | /* pop userdata */
2582 | lua_pop(L, 1);
2583 |
2584 | return ngx_zookeeper_lua_error(L, "awatch", ngx_zerr(rc));
2585 |
2586 | nomem:
2587 |
2588 | ngx_rwlock_unlock(&zmcf->lock);
2589 |
2590 | if (data != NULL) {
2591 |
2592 | dereference(data);
2593 |
2594 | /* pop userdata */
2595 | lua_pop(L, 1);
2596 | }
2597 |
2598 | return ngx_zookeeper_lua_error(L, "awatch", "no memory");
2599 | }
2600 |
2601 |
2602 | static void
2603 | ngx_zookeeper_unwatch_ready(int rc, const void *p)
2604 | {
2605 | datatype_t *data = (datatype_t *) p;
2606 |
2607 | if (data == NULL)
2608 | return;
2609 |
2610 | if (data->refs == 1)
2611 | goto end;
2612 |
2613 | ngx_rwlock_wlock(&data->lock);
2614 |
2615 | if (rc != ZOK && rc != ZUNIMPLEMENTED)
2616 | data->error = ngx_zerr(rc);
2617 |
2618 | data->completed = 1;
2619 |
2620 | ngx_rwlock_unlock(&data->lock);
2621 |
2622 | end:
2623 |
2624 | dereference(data);
2625 | }
2626 |
2627 |
2628 | static int
2629 | ngx_zookeeper_aunwatch(lua_State *L)
2630 | {
2631 | int rc;
2632 | datatype_t *data;
2633 | str_t path;
2634 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
2635 | int watch_type;
2636 | ngx_int_t index;
2637 | watched_t *w;
2638 |
2639 | ngx_http_zookeeper_check_mon();
2640 |
2641 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
2642 | ngx_zookeeper_lua_module);
2643 |
2644 | if (zmcf->zoo.handle == NULL)
2645 | return ngx_zookeeper_lua_error(L, "aunwatch",
2646 | "zookeeper handle is nil");
2647 |
2648 | if (zmcf->zoo.connected == NGX_ERROR)
2649 | return ngx_zookeeper_lua_error(L, "aunwatch", "not connected");
2650 |
2651 | if (lua_gettop(L) != 2)
2652 | return ngx_zookeeper_lua_error(L, "aunwatch",
2653 | "2 arguments expected");
2654 |
2655 | watch_type = luaL_checkinteger(L, 2);
2656 |
2657 | if (watch_type != ZOO_CHILD_EVENT && watch_type != ZOO_CHANGED_EVENT)
2658 | return ngx_zookeeper_lua_error(L, "aunwatch", "invalid watch type");
2659 |
2660 | ngx_rwlock_wlock(&zmcf->lock);
2661 |
2662 | path.data = (char *) luaL_checklstring(L, 1, &path.len);
2663 |
2664 | index = ngx_zookeeper_awatch_exists(path, watch_type);
2665 | if (index == NGX_DECLINED) {
2666 |
2667 | ngx_rwlock_unlock(&zmcf->lock);
2668 | return ngx_zookeeper_lua_error(L, "aunwatch", "not exists");
2669 | }
2670 |
2671 | data = new(L);
2672 | if (data == NULL) {
2673 |
2674 | ngx_rwlock_unlock(&zmcf->lock);
2675 | return ngx_zookeeper_lua_error(L, "aunwatch", "no memory");
2676 | }
2677 |
2678 | data->completition_fn = ngx_zookeeper_void_completition;
2679 |
2680 | rc = zoo_aremove_watches(zmcf->zoo.handle, path.data, watch_type,
2681 | ngx_zookeeper_watch, (void *) index, 0,
2682 | (void_completion_t *) ngx_zookeeper_unwatch_ready, data);
2683 |
2684 | if (rc == ZOK || rc == ZNOWATCHER) {
2685 |
2686 | w = zmcf->watched->elts;
2687 |
2688 | ngx_zookeeper_awatch_free_slot(w + index);
2689 |
2690 | if (rc == ZNOWATCHER) {
2691 |
2692 | dereference(data);
2693 | data->completed = 1;
2694 | }
2695 |
2696 | ngx_rwlock_unlock(&zmcf->lock);
2697 | return 1;
2698 | }
2699 |
2700 | ngx_rwlock_unlock(&zmcf->lock);
2701 |
2702 | dereference(data);
2703 |
2704 | /* pop userdata */
2705 | lua_pop(L, 1);
2706 |
2707 | return ngx_zookeeper_lua_error(L, "aunwatch", ngx_zerr(rc));
2708 | }
2709 |
2710 |
2711 | static int
2712 | ngx_zookeeper_changed(lua_State *L)
2713 | {
2714 | ngx_http_zookeeper_lua_main_conf_t *zmcf;
2715 | watched_t *w;
2716 | ngx_uint_t j;
2717 | int i = 1, used_slots = 0;
2718 |
2719 | zmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
2720 | ngx_zookeeper_lua_module);
2721 |
2722 | if (lua_gettop(L))
2723 | return ngx_zookeeper_lua_error(L, "changed", "no arguments expected");
2724 |
2725 | w = zmcf->watched->elts;
2726 |
2727 | lua_newtable(L);
2728 |
2729 | ngx_rwlock_wlock(&zmcf->lock);
2730 |
2731 | for (j = 0; j < zmcf->watched->nelts; j++) {
2732 |
2733 | if (w[j].path.data)
2734 | used_slots++;
2735 |
2736 | if (!w[j].changed || !w[j].path.data)
2737 | continue;
2738 |
2739 | lua_newtable(L);
2740 |
2741 | lua_pushlstring(L, (char *) w[j].path.data, w[j].path.len);
2742 | lua_rawseti(L, -2, 1);
2743 |
2744 | lua_pushinteger(L, w[j].watch_type);
2745 | lua_rawseti(L, -2, 2);
2746 |
2747 | lua_rawseti(L, -2, i++);
2748 |
2749 | ngx_zookeeper_awatch_free_slot(w + j);
2750 | }
2751 |
2752 | if (used_slots == 0)
2753 | zmcf->watched->nelts = 0;
2754 |
2755 | ngx_rwlock_unlock(&zmcf->lock);
2756 |
2757 | return 1;
2758 | }
2759 |
--------------------------------------------------------------------------------
/patches/lua-cjson-Makefile.patch:
--------------------------------------------------------------------------------
1 | --- lua-cjson/Makefile 2016-11-07 08:47:47.000000000 +0300
2 | +++ lua-cjson/Makefile 2016-10-26 00:04:44.000000000 +0300
3 | @@ -13,12 +13,12 @@
4 | ##### Build defaults #####
5 | LUA_VERSION = 5.1
6 | TARGET = cjson.so
7 | -PREFIX = /usr/local
8 | +PREFIX ?= /usr/local
9 | #CFLAGS = -g -Wall -pedantic -fno-inline
10 | CFLAGS = -O3 -Wall -pedantic -DNDEBUG
11 | CJSON_CFLAGS = -fpic
12 | CJSON_LDFLAGS = -shared
13 | -LUA_INCLUDE_DIR ?= $(PREFIX)/include
14 | +LUA_INCLUDE_DIR ?= $(PREFIX)/include/luajit-2.1
15 | LUA_CMODULE_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION)
16 | LUA_MODULE_DIR ?= $(PREFIX)/share/lua/$(LUA_VERSION)
17 | LUA_BIN_DIR ?= $(PREFIX)/bin
18 |
--------------------------------------------------------------------------------
/scripts/restart.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DIR=$(pwd)
4 | export LD_LIBRARY_PATH=$DIR/lib
5 | export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
6 | ./sbin/nginx -s reload -p $DIR
--------------------------------------------------------------------------------
/scripts/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DIR=$(pwd)
4 | export LD_LIBRARY_PATH=$DIR/lib
5 | export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
6 | ./sbin/nginx -p $DIR
--------------------------------------------------------------------------------
/scripts/stop.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DIR=$(pwd)
4 | export LD_LIBRARY_PATH=$DIR/lib
5 | export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
6 | ./sbin/nginx -s stop -p $DIR
--------------------------------------------------------------------------------
/t/directives.t:
--------------------------------------------------------------------------------
1 | use Test::Nginx::Socket;
2 | use Test::Nginx::Socket::Lua::Stream;
3 |
4 | $ENV{TEST_NGINX_ZOOKEEPER_PORT} ||= 2181;
5 |
6 | repeat_each(1);
7 |
8 | plan tests => repeat_each() * 2 * blocks();
9 |
10 | run_tests();
11 |
12 | __DATA__
13 |
14 | === TEST 1: Persistent node
15 | --- http_config
16 | lua_load_resty_core off;
17 | lua_package_path "lua/?.lua;;";
18 |
19 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
20 | zookeeper_log_level debug;
21 | zookeeper_recv_timeout 60000;
22 |
23 | lua_shared_dict config 64k;
24 | lua_shared_dict zoo_cache 10m;
25 |
26 | init_by_lua_block {
27 | ngx.shared.config:set("zoo.cache.on", false)
28 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
29 | }
30 | --- config
31 | zookeeper_node /test node data;
32 | location /test {
33 | content_by_lua_block {
34 | local zoo = require "zoo"
35 | ngx.sleep(3)
36 |
37 | local val, stat, err = zoo.get("/test/node")
38 | if not val then
39 | ngx.say(err)
40 | return
41 | end
42 | ngx.say(val, " ", stat.ephemeralOwner == 0)
43 |
44 | zoo.delete_recursive("/test")
45 | }
46 | }
47 | --- timeout: 4
48 | --- request
49 | GET /test
50 | --- response_body
51 | data true
52 |
53 |
54 | === TEST 2: Ethemeral node
55 | --- http_config
56 | lua_load_resty_core off;
57 | lua_package_path "lua/?.lua;;";
58 |
59 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
60 | zookeeper_log_level debug;
61 | zookeeper_recv_timeout 60000;
62 |
63 | lua_shared_dict config 64k;
64 | lua_shared_dict zoo_cache 10m;
65 |
66 | init_by_lua_block {
67 | ngx.shared.config:set("zoo.cache.on", false)
68 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
69 | }
70 | --- config
71 | zookeeper_ephemeral_node /test node data;
72 | location /test {
73 | content_by_lua_block {
74 | local zoo = require "zoo"
75 | ngx.sleep(3)
76 |
77 | local val, stat, err = zoo.get("/test/node")
78 | if not val then
79 | ngx.say(err)
80 | return
81 | end
82 | ngx.say(val, " ", stat.ephemeralOwner ~= 0)
83 |
84 | zoo.delete_recursive("/test")
85 | }
86 | }
87 | --- timeout: 4
88 | --- request
89 | GET /test
90 | --- response_body
91 | data true
92 |
93 |
94 | === TEST 3: Register port
95 | --- http_config
96 | lua_load_resty_core off;
97 | lua_package_path "lua/?.lua;;";
98 |
99 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
100 | zookeeper_log_level debug;
101 | zookeeper_recv_timeout 60000;
102 | zookeeper_inactive_time 1;
103 |
104 | lua_shared_dict config 64k;
105 | lua_shared_dict zoo_cache 10m;
106 |
107 | init_by_lua_block {
108 | ngx.shared.config:set("zoo.cache.on", false)
109 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
110 | }
111 | --- config
112 | zookeeper_register_port /test 8888 data;
113 | location /test {
114 | content_by_lua_block {
115 | local zoo = require "zoo"
116 | ngx.sleep(3)
117 |
118 | local nodes, err = zoo.childrens("/test")
119 | if not nodes then
120 | ngx.say(err)
121 | return
122 | end
123 |
124 | for _,node in ipairs(nodes) do
125 | local val, stat, err = zoo.get("/test/" .. node)
126 | if not val then
127 | ngx.say(err)
128 | return
129 | end
130 | ngx.say(node:match(":(%d+)$"), " ", val, " ", stat.ephemeralOwner ~= 0)
131 | end
132 |
133 | zoo.delete_recursive("/test")
134 | }
135 | }
136 | --- timeout: 4
137 | --- request
138 | GET /test
139 | --- response_body_like
140 | 8888 data true
141 |
--------------------------------------------------------------------------------
/t/inactive.t:
--------------------------------------------------------------------------------
1 | use Test::Nginx::Socket;
2 | use Test::Nginx::Socket::Lua::Stream;
3 |
4 | $ENV{TEST_NGINX_ZOOKEEPER_PORT} ||= 2181;
5 |
6 | repeat_each(1);
7 |
8 | plan tests => repeat_each() * 2 * blocks();
9 |
10 | run_tests();
11 |
12 | __DATA__
13 |
14 |
15 | === TEST 1: Test 1
16 | --- http_config
17 | lua_load_resty_core off;
18 | lua_package_path "lua/?.lua;;";
19 |
20 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
21 | zookeeper_log_level debug;
22 | zookeeper_recv_timeout 60000;
23 | zookeeper_inactive_time 1;
24 |
25 | lua_shared_dict config 64k;
26 | lua_shared_dict zoo_cache 10m;
27 |
28 | init_by_lua_block {
29 | ngx.shared.config:set("zoo.cache.on", false)
30 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
31 | }
32 | --- config
33 | location /test {
34 | content_by_lua_block {
35 | local zoo = require "zoo"
36 |
37 | zoo.delete_recursive("/test")
38 |
39 | for i=1,5 do
40 | local ok, err = zoo.create("/test", tostring(i))
41 | if not ok then
42 | ngx.say(err)
43 | return
44 | end
45 |
46 | ngx.sleep(2)
47 |
48 | local val, _, err = zoo.get("/test")
49 | if not val then
50 | ngx.say(err)
51 | return
52 | end
53 |
54 | ngx.say(val)
55 |
56 | zoo.delete_recursive("/test")
57 |
58 | ngx.sleep(2)
59 | end
60 | }
61 | }
62 | --- timeout: 25
63 | --- request
64 | GET /test
65 | --- response_body_like
66 | 1
67 | 2
68 | 3
69 | 4
70 | 5
71 |
--------------------------------------------------------------------------------
/t/lua:
--------------------------------------------------------------------------------
1 | ../lua
--------------------------------------------------------------------------------
/t/operations.t:
--------------------------------------------------------------------------------
1 | use Test::Nginx::Socket;
2 | use Test::Nginx::Socket::Lua::Stream;
3 |
4 | $ENV{TEST_NGINX_ZOOKEEPER_PORT} ||= 2181;
5 |
6 | repeat_each(1);
7 |
8 | plan tests => repeat_each() * 2 * blocks();
9 |
10 | run_tests();
11 |
12 | __DATA__
13 |
14 | === TEST 1: create & get & delete & get
15 | --- http_config
16 | lua_load_resty_core off;
17 | lua_package_path "lua/?.lua;;";
18 |
19 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
20 | zookeeper_log_level debug;
21 | zookeeper_recv_timeout 60000;
22 | zookeeper_inactive_time 1;
23 |
24 | lua_shared_dict config 64k;
25 | lua_shared_dict zoo_cache 10m;
26 |
27 | init_by_lua_block {
28 | ngx.shared.config:set("zoo.cache.on", false)
29 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
30 | }
31 | --- config
32 | location /test {
33 | content_by_lua_block {
34 | local zoo = require "zoo"
35 |
36 | zoo.delete_recursive(ngx.var.arg_znode)
37 |
38 | local path, err = zoo.create(ngx.var.arg_znode, ngx.var.arg_value)
39 | ngx.say(path, " ", err)
40 |
41 | local val, _, err = zoo.get(ngx.var.arg_znode)
42 | ngx.say(val, " ", err)
43 |
44 | ok, err = zoo.delete(ngx.var.arg_znode)
45 | ngx.say(ok, " ", err)
46 |
47 | local val, _, err = zoo.get(ngx.var.arg_znode)
48 | ngx.say(val, " ", err)
49 | }
50 | }
51 | --- timeout: 1
52 | --- request
53 | GET /test?znode=/test&value=test
54 | --- response_body
55 | /test nil
56 | test nil
57 | true nil
58 | nil Znode does not exist
59 |
60 |
61 | === TEST 2: create failed
62 | --- http_config
63 | lua_load_resty_core off;
64 | lua_package_path "lua/?.lua;;";
65 |
66 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
67 | zookeeper_log_level debug;
68 | zookeeper_recv_timeout 60000;
69 | zookeeper_inactive_time 1;
70 |
71 | lua_shared_dict config 64k;
72 | lua_shared_dict zoo_cache 10m;
73 |
74 | init_by_lua_block {
75 | ngx.shared.config:set("zoo.cache.on", false)
76 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
77 | }
78 | --- config
79 | location /test {
80 | content_by_lua_block {
81 | local zoo = require "zoo"
82 | local ok, err = zoo.create(ngx.var.arg_znode)
83 | ngx.say(ok, " ", err)
84 | }
85 | }
86 | --- timeout: 1
87 | --- request
88 | GET /test?znode=/test/no/node/found
89 | --- response_body
90 | nil Znode does not exist
91 |
92 |
93 | === TEST 3: create path & get
94 | --- http_config
95 | lua_load_resty_core off;
96 | lua_package_path "lua/?.lua;;";
97 |
98 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
99 | zookeeper_log_level debug;
100 | zookeeper_recv_timeout 60000;
101 | zookeeper_inactive_time 1;
102 |
103 | lua_shared_dict config 64k;
104 | lua_shared_dict zoo_cache 10m;
105 |
106 | init_by_lua_block {
107 | ngx.shared.config:set("zoo.cache.on", false)
108 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
109 | }
110 | --- config
111 | location /test {
112 | content_by_lua_block {
113 | local zoo = require "zoo"
114 |
115 | zoo.delete_recursive(ngx.var.arg_znode)
116 |
117 | local ok, err = zoo.create_path(ngx.var.arg_znode)
118 | ngx.say(ok, " ", err)
119 |
120 | local path, err = zoo.create(ngx.var.arg_znode .. "/0", ngx.var.arg_value)
121 | ngx.say(path, " ", err)
122 |
123 | local val, _, err = zoo.get(ngx.var.arg_znode .. "/0")
124 | ngx.say(val, " ", err)
125 |
126 | zoo.delete_recursive("/test")
127 | }
128 | }
129 | --- timeout: 1
130 | --- request
131 | GET /test?znode=/test/1/2/3&value=test
132 | --- response_body
133 | true nil
134 | /test/1/2/3/0 nil
135 | test nil
136 |
137 |
138 | === TEST 4: create & get & set & get & delete
139 | --- http_config
140 | lua_load_resty_core off;
141 | lua_package_path "lua/?.lua;;";
142 |
143 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
144 | zookeeper_log_level debug;
145 | zookeeper_recv_timeout 60000;
146 | zookeeper_inactive_time 1;
147 |
148 | lua_shared_dict config 64k;
149 | lua_shared_dict zoo_cache 10m;
150 |
151 | init_by_lua_block {
152 | ngx.shared.config:set("zoo.cache.on", false)
153 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
154 | }
155 | --- config
156 | location /test {
157 | content_by_lua_block {
158 | local zoo = require "zoo"
159 |
160 | zoo.delete_recursive(ngx.var.arg_znode)
161 |
162 | local path, err = zoo.create(ngx.var.arg_znode, ngx.var.arg_value)
163 | ngx.say(path, " ", err)
164 |
165 | local val, _, err = zoo.get(ngx.var.arg_znode)
166 | ngx.say(val, " ", err)
167 |
168 | local stat, err = zoo.set(ngx.var.arg_znode, ngx.var.arg_value2)
169 | ngx.say(stat ~= nil, " ", err)
170 |
171 | local val, _, err = zoo.get(ngx.var.arg_znode)
172 | ngx.say(val, " ", err)
173 |
174 | zoo.delete_recursive(ngx.var.arg_znode)
175 |
176 | local val, _, err = zoo.get(ngx.var.arg_znode)
177 | ngx.say(val, " ", err)
178 | }
179 | }
180 | --- timeout: 1
181 | --- request
182 | GET /test?znode=/test&value=test&value2=test2
183 | --- response_body
184 | /test nil
185 | test nil
186 | true nil
187 | test2 nil
188 | nil Znode does not exist
189 |
190 |
191 | === TEST 5: create & childrens
192 | --- http_config
193 | lua_load_resty_core off;
194 | lua_package_path "lua/?.lua;;";
195 |
196 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
197 | zookeeper_log_level debug;
198 | zookeeper_recv_timeout 60000;
199 | zookeeper_inactive_time 1;
200 |
201 | lua_shared_dict config 64k;
202 | lua_shared_dict zoo_cache 10m;
203 |
204 | init_by_lua_block {
205 | ngx.shared.config:set("zoo.cache.on", false)
206 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
207 | }
208 | --- config
209 | location /test {
210 | content_by_lua_block {
211 | local zoo = require "zoo"
212 |
213 | zoo.delete_recursive(ngx.var.arg_znode)
214 |
215 | local ok, err = zoo.create(ngx.var.arg_znode)
216 | ngx.say(ok, " ", err)
217 |
218 | for i=1,5 do
219 | local path, err = zoo.create(ngx.var.arg_znode .. "/" .. i, i)
220 | ngx.say(path, " ", err)
221 | end
222 |
223 | local childrens, err = zoo.childrens(ngx.var.arg_znode)
224 | ngx.say(childrens ~= nil, " ", err)
225 | for _,c in ipairs(childrens or {})
226 | do
227 | local val, stat, err = zoo.get(ngx.var.arg_znode .. "/" .. c)
228 | ngx.say(val, " ", err)
229 | end
230 |
231 | zoo.delete_recursive(ngx.var.arg_znode)
232 | }
233 | }
234 | --- timeout: 1
235 | --- request
236 | GET /test?znode=/test
237 | --- response_body
238 | /test nil
239 | /test/1 nil
240 | /test/2 nil
241 | /test/3 nil
242 | /test/4 nil
243 | /test/5 nil
244 | true nil
245 | 1 nil
246 | 2 nil
247 | 3 nil
248 | 4 nil
249 | 5 nil
250 |
251 |
252 | === TEST 6: create & tree
253 | --- http_config
254 | lua_load_resty_core off;
255 | lua_package_path "lua/?.lua;;";
256 |
257 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
258 | zookeeper_log_level debug;
259 | zookeeper_recv_timeout 60000;
260 | zookeeper_inactive_time 1;
261 |
262 | lua_shared_dict config 64k;
263 | lua_shared_dict zoo_cache 10m;
264 |
265 | init_by_lua_block {
266 | ngx.shared.config:set("zoo.cache.on", false)
267 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
268 | }
269 | --- config
270 | location /test {
271 | content_by_lua_block {
272 | local zoo = require "zoo"
273 | local cjson = require "cjson"
274 |
275 | zoo.delete_recursive(ngx.var.arg_znode)
276 |
277 | local ok, err = zoo.create(ngx.var.arg_znode)
278 | ngx.say(ok, " ", err)
279 |
280 | for i=1,3 do
281 | zoo.create(ngx.var.arg_znode .. "/" .. i, i)
282 | for j=11,13 do
283 | zoo.create(ngx.var.arg_znode .. "/" .. i .. "/" .. j, j)
284 | end
285 | end
286 |
287 | local tree, err = zoo.tree(ngx.var.arg_znode)
288 | ngx.say(tree ~= nil, " ", err)
289 |
290 | if tree ~= nil then
291 | ngx.say(cjson.encode(tree))
292 | end
293 |
294 | zoo.delete_recursive(ngx.var.arg_znode)
295 | }
296 | }
297 | --- timeout: 1
298 | --- request
299 | GET /test?znode=/test
300 | --- response_body
301 | /test nil
302 | true nil
303 | {"1":{"12":"12","value":"1","11":"11","13":"13"},"2":{"12":"12","value":"2","11":"11","13":"13"},"3":{"12":"12","value":"3","11":"11","13":"13"}}
304 |
305 |
306 | === TEST 7: create & set cas
307 | --- http_config
308 | lua_load_resty_core off;
309 | lua_package_path "lua/?.lua;;";
310 |
311 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
312 | zookeeper_log_level debug;
313 | zookeeper_recv_timeout 60000;
314 | zookeeper_inactive_time 1;
315 |
316 | lua_shared_dict config 64k;
317 | lua_shared_dict zoo_cache 10m;
318 |
319 | init_by_lua_block {
320 | ngx.shared.config:set("zoo.cache.on", false)
321 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
322 | }
323 | --- config
324 | location /test {
325 | content_by_lua_block {
326 | local zoo = require "zoo"
327 |
328 | zoo.delete_recursive(ngx.var.arg_znode)
329 |
330 | local path, err = zoo.create(ngx.var.arg_znode, ngx.var.arg_value1)
331 | ngx.say(path, " ", err)
332 |
333 | local val, stat, err = zoo.get(ngx.var.arg_znode)
334 | ngx.say(val, " ", err)
335 |
336 | local stat2, err = zoo.set(ngx.var.arg_znode, "***")
337 | ngx.say(stat2 ~= nil, " ", err)
338 |
339 | local s, err = zoo.set(ngx.var.arg_znode, ngx.var.arg_value2, stat.version)
340 | ngx.say(s == nil, " ", err)
341 |
342 | local s, err = zoo.set(ngx.var.arg_znode, ngx.var.arg_value2, stat2.version)
343 | ngx.say(s ~= nil, " ", err)
344 |
345 | local val, stat, err = zoo.get(ngx.var.arg_znode)
346 | ngx.say(val, " ", err)
347 |
348 | zoo.delete_recursive(ngx.var.arg_znode)
349 | }
350 | }
351 | --- timeout: 1
352 | --- request
353 | GET /test?znode=/test&value1=test&value2=test2
354 | --- response_body
355 | /test nil
356 | test nil
357 | true nil
358 | true Version conflict
359 | true nil
360 | test2 nil
361 |
362 |
363 | === TEST 8: create path
364 | --- http_config
365 | lua_load_resty_core off;
366 | lua_package_path "lua/?.lua;;";
367 |
368 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
369 | zookeeper_log_level debug;
370 | zookeeper_recv_timeout 60000;
371 | zookeeper_inactive_time 1;
372 |
373 | lua_shared_dict config 64k;
374 | lua_shared_dict zoo_cache 10m;
375 |
376 | init_by_lua_block {
377 | ngx.shared.config:set("zoo.cache.on", false)
378 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
379 | }
380 | --- config
381 | location /test {
382 | content_by_lua_block {
383 | local zoo = require "zoo"
384 |
385 | local ok, err = zoo.create_path(ngx.var.arg_znode)
386 | ngx.say(ok, " ", err)
387 |
388 | local s, err = zoo.set(ngx.var.arg_znode, ngx.var.arg_value)
389 | ngx.say(s ~= nil, " ", err)
390 |
391 | local val, _, err = zoo.get(ngx.var.arg_znode)
392 | ngx.say(val, " ", err)
393 |
394 | zoo.delete_recursive(ngx.var.arg_znode)
395 | }
396 | }
397 | --- timeout: 1
398 | --- request
399 | GET /test?znode=/test/a/b/c/d/e&value=test
400 | --- response_body
401 | true nil
402 | true nil
403 | test nil
404 |
405 |
--------------------------------------------------------------------------------
/t/watch.t:
--------------------------------------------------------------------------------
1 | use Test::Nginx::Socket;
2 | use Test::Nginx::Socket::Lua::Stream;
3 |
4 | $ENV{TEST_NGINX_ZOOKEEPER_PORT} ||= 2181;
5 |
6 | repeat_each(1);
7 |
8 | plan tests => repeat_each() * 2 * blocks();
9 |
10 | run_tests();
11 |
12 | __DATA__
13 |
14 | === TEST 1: data watch
15 | --- http_config
16 | lua_load_resty_core off;
17 | lua_package_path "lua/?.lua;;";
18 |
19 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
20 | zookeeper_log_level debug;
21 | zookeeper_recv_timeout 60000;
22 | zookeeper_inactive_time 1;
23 |
24 | lua_shared_dict config 64k;
25 | lua_shared_dict zoo_cache 10m;
26 |
27 | init_by_lua_block {
28 | ngx.shared.config:set("zoo.cache.on", false)
29 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
30 | ngx.shared.config:set("zoo.watch.interval", 0.1)
31 | }
32 | --- config
33 | location /test {
34 | content_by_lua_block {
35 | local zoo = require "zoo"
36 |
37 | zoo.delete_recursive(ngx.var.arg_znode)
38 |
39 | local path, err = zoo.create(ngx.var.arg_znode, ngx.var.arg_value)
40 | ngx.say(path, " ", err)
41 |
42 | local t = {}
43 |
44 | local function on_event(ctx)
45 | local data = assert(zoo.watch(ctx.path, ctx.watcher_type, on_event, ctx))
46 | table.insert(t, data)
47 | end
48 |
49 | on_event {
50 | watcher_type = zoo.WatcherType.DATA,
51 | path = ngx.var.arg_znode
52 | }
53 |
54 | for j=1,3 do
55 | ngx.sleep(2)
56 | local s, err = zoo.set(ngx.var.arg_znode, j)
57 | ngx.say(s ~= nil, " ", err)
58 | end
59 |
60 | ngx.sleep(2)
61 |
62 | local ok, err = zoo.unwatch(ngx.var.arg_znode, zoo.WatcherType.DATA)
63 | ngx.say("unwatch:", ok, " ", err)
64 |
65 | for _,v in ipairs(t) do
66 | ngx.say(v)
67 | end
68 |
69 | zoo.delete_recursive(ngx.var.arg_znode)
70 | }
71 | }
72 | --- timeout: 12
73 | --- request
74 | GET /test?znode=/test&value=0
75 | --- response_body
76 | /test nil
77 | true nil
78 | true nil
79 | true nil
80 | unwatch:true nil
81 | 0
82 | 1
83 | 2
84 | 3
85 |
86 |
87 | === TEST 2: data watch (delete)
88 | --- http_config
89 | lua_load_resty_core off;
90 | lua_package_path "lua/?.lua;;";
91 |
92 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
93 | zookeeper_log_level debug;
94 | zookeeper_recv_timeout 60000;
95 | zookeeper_inactive_time 1;
96 |
97 | lua_shared_dict config 64k;
98 | lua_shared_dict zoo_cache 10m;
99 |
100 | init_by_lua_block {
101 | ngx.shared.config:set("zoo.cache.on", false)
102 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
103 | ngx.shared.config:set("zoo.watch.interval", 0.1)
104 | }
105 | --- config
106 | location /test {
107 | content_by_lua_block {
108 | local zoo = require "zoo"
109 |
110 | zoo.delete_recursive(ngx.var.arg_znode)
111 |
112 | local path, err = zoo.create(ngx.var.arg_znode, ngx.var.arg_value)
113 | ngx.say(path, " ", err)
114 |
115 | local t = {}
116 |
117 | local function on_event(ctx)
118 | local data, err = zoo.watch(ctx.path, ctx.watcher_type, on_event, ctx)
119 | table.insert(t, data or err)
120 | end
121 |
122 | on_event {
123 | watcher_type = zoo.WatcherType.DATA,
124 | path = ngx.var.arg_znode
125 | }
126 |
127 | for j=1,3 do
128 | ngx.sleep(1)
129 | local s, err = zoo.set(ngx.var.arg_znode, j)
130 | ngx.say(s ~= nil, " ", err)
131 | end
132 |
133 | ngx.sleep(1)
134 |
135 | local ok, err = zoo.delete(ngx.var.arg_znode)
136 | ngx.say("deleted:", ok, " ", err)
137 |
138 | ngx.sleep(1)
139 |
140 | for _,v in ipairs(t) do
141 | ngx.say(v)
142 | end
143 |
144 | zoo.delete_recursive(ngx.var.arg_znode)
145 | }
146 | }
147 | --- timeout: 7
148 | --- request
149 | GET /test?znode=/test&value=0
150 | --- response_body
151 | /test nil
152 | true nil
153 | true nil
154 | true nil
155 | deleted:true nil
156 | 0
157 | 1
158 | 2
159 | 3
160 | Znode does not exist
161 |
162 |
163 | === TEST 3: childrens watch
164 | --- http_config
165 | lua_load_resty_core off;
166 | lua_package_path "lua/?.lua;;";
167 |
168 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
169 | zookeeper_log_level debug;
170 | zookeeper_recv_timeout 60000;
171 | zookeeper_inactive_time 1;
172 |
173 | lua_shared_dict config 64k;
174 | lua_shared_dict zoo_cache 10m;
175 |
176 | init_by_lua_block {
177 | ngx.shared.config:set("zoo.cache.on", false)
178 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
179 | ngx.shared.config:set("zoo.watch.interval", 0.1)
180 | }
181 | --- config
182 | location /test {
183 | content_by_lua_block {
184 | local zoo = require "zoo"
185 |
186 | zoo.delete_recursive(ngx.var.arg_znode)
187 |
188 | local path, err = zoo.create(ngx.var.arg_znode, ngx.var.arg_value)
189 | ngx.say(path, " ", err)
190 |
191 | local t = {}
192 |
193 | local function on_event(ctx)
194 | local data = assert(zoo.watch(ctx.path, ctx.watcher_type, on_event, ctx))
195 | table.insert(t, data)
196 | end
197 |
198 | on_event {
199 | watcher_type = zoo.WatcherType.CHILDREN,
200 | path = ngx.var.arg_znode
201 | }
202 |
203 | for j=1,3 do
204 | ngx.sleep(1)
205 | local path, err = zoo.create(ngx.var.arg_znode .. "/" .. j)
206 | ngx.say(path, " ", err)
207 | end
208 |
209 | ngx.sleep(1)
210 |
211 | local ok, err = zoo.unwatch(ngx.var.arg_znode, zoo.WatcherType.CHILDREN)
212 | ngx.say("unwatch:", ok, " ", err)
213 |
214 | for _,v in ipairs(t) do
215 | for _,c in ipairs(v) do
216 | ngx.print(c)
217 | end
218 | ngx.say()
219 | end
220 |
221 | zoo.delete_recursive(ngx.var.arg_znode)
222 | }
223 | }
224 | --- timeout: 6
225 | --- request
226 | GET /test?znode=/test&value=0
227 | --- response_body_like
228 | /test nil
229 | /test/1 nil
230 | /test/2 nil
231 | /test/3 nil
232 | unwatch:true nil
233 |
234 | 1
235 | 12
236 | 123
237 |
238 |
239 | === TEST 4: childrens watch (delete)
240 | --- http_config
241 | lua_load_resty_core off;
242 | lua_package_path "lua/?.lua;;";
243 |
244 | zookeeper 127.0.0.1:$TEST_NGINX_ZOOKEEPER_PORT;
245 | zookeeper_log_level debug;
246 | zookeeper_recv_timeout 60000;
247 | zookeeper_inactive_time 1;
248 |
249 | lua_shared_dict config 64k;
250 | lua_shared_dict zoo_cache 10m;
251 |
252 | init_by_lua_block {
253 | ngx.shared.config:set("zoo.cache.on", false)
254 | ngx.shared.config:set("zoo.cache.path.ttl", "{}")
255 | ngx.shared.config:set("zoo.watch.interval", 0.1)
256 | }
257 | --- config
258 | location /test {
259 | content_by_lua_block {
260 | local zoo = require "zoo"
261 |
262 | zoo.delete_recursive(ngx.var.arg_znode)
263 |
264 | local path, err = zoo.create(ngx.var.arg_znode, ngx.var.arg_value)
265 | ngx.say(path, " ", err)
266 |
267 | local t = {}
268 |
269 | local function on_event(ctx)
270 | local data, err = zoo.watch(ctx.path, ctx.watcher_type, on_event, ctx)
271 | table.insert(t, data or { err })
272 | end
273 |
274 | on_event {
275 | watcher_type = zoo.WatcherType.CHILDREN,
276 | path = ngx.var.arg_znode
277 | }
278 |
279 | for j=1,3 do
280 | ngx.sleep(1)
281 | local path, err = zoo.create(ngx.var.arg_znode .. "/" .. j)
282 | ngx.say(path, " ", err)
283 | end
284 |
285 | ngx.sleep(1)
286 |
287 | for j=1,3 do
288 | local ok, err = zoo.delete(ngx.var.arg_znode .. "/" .. j)
289 | ngx.say("delete:", ok, " ", err)
290 | end
291 |
292 | ngx.sleep(1)
293 |
294 | local ok, err = zoo.delete(ngx.var.arg_znode)
295 | ngx.say("delete node:", ok, " ", err)
296 |
297 | ngx.sleep(1)
298 |
299 | for _,v in ipairs(t) do
300 | ngx.print(#v .. ":")
301 | for _,c in ipairs(v) do
302 | ngx.print(c)
303 | end
304 | ngx.say()
305 | end
306 | }
307 | }
308 | --- timeout: 10
309 | --- request
310 | GET /test?znode=/test&value=0
311 | --- response_body
312 | /test nil
313 | /test/1 nil
314 | /test/2 nil
315 | /test/3 nil
316 | delete:true nil
317 | delete:true nil
318 | delete:true nil
319 | delete node:true nil
320 | 0:
321 | 1:1
322 | 2:12
323 | 3:123
324 | 0:
325 | 1:Znode does not exist
326 |
327 |
--------------------------------------------------------------------------------
/t/zoo.jmx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | false
7 | false
8 |
9 |
10 |
11 | HOST
12 | localhost
13 | =
14 |
15 |
16 | PORT
17 | 12181
18 | =
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | continue
27 |
28 | false
29 | 1
30 |
31 | 1
32 | 0
33 | 1514488771000
34 | 1514488771000
35 | false
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | ${HOST}
45 | ${PORT}
46 |
47 |
48 |
49 |
50 | /zoo/create?znode=/test
51 | POST
52 | true
53 | false
54 | true
55 | false
56 | false
57 |
58 |
59 |
60 |
61 |
62 | continue
63 |
64 | false
65 | -1
66 |
67 | 100
68 | 10
69 | 1478035966000
70 | 1478035966000
71 | false
72 |
73 |
74 |
75 |
76 |
77 | 1
78 |
79 | 1
80 | I
81 |
82 | false
83 |
84 |
85 |
86 | true
87 | -1
88 |
89 |
90 |
91 |
92 |
93 |
94 | ${HOST}
95 | ${PORT}
96 |
97 |
98 |
99 |
100 | /zoo/create?znode=/test/test_${I}&value=XXX
101 | POST
102 | true
103 | false
104 | true
105 | false
106 | false
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | ${HOST}
115 | ${PORT}
116 |
117 |
118 |
119 |
120 | /zoo/set?znode=/test/test_${I}&value=xxxxxx
121 | POST
122 | true
123 | false
124 | true
125 | false
126 | false
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | ${HOST}
135 | ${PORT}
136 |
137 |
138 |
139 |
140 | /zoo/get?znode=/test/test_${I}
141 | GET
142 | true
143 | false
144 | true
145 | false
146 | false
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 | ${HOST}
155 | ${PORT}
156 |
157 |
158 |
159 |
160 | /zoo/delete?znode=/test/test_${I}
161 | POST
162 | true
163 | false
164 | true
165 | false
166 | false
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 | ${HOST}
175 | ${PORT}
176 |
177 |
178 |
179 |
180 | /zoo/childrens?znode=/nginx
181 | GET
182 | true
183 | false
184 | true
185 | false
186 | false
187 |
188 |
189 |
190 |
191 |
192 |
193 | false
194 |
195 | saveConfig
196 |
197 |
198 | true
199 | true
200 | true
201 |
202 | true
203 | true
204 | true
205 | true
206 | false
207 | true
208 | true
209 | false
210 | false
211 | false
212 | false
213 | false
214 | false
215 | false
216 | false
217 | 0
218 | true
219 |
220 |
221 |
222 |
223 |
224 |
225 | false
226 |
227 | saveConfig
228 |
229 |
230 | true
231 | true
232 | true
233 |
234 | true
235 | true
236 | true
237 | true
238 | false
239 | true
240 | true
241 | false
242 | false
243 | false
244 | false
245 | false
246 | false
247 | false
248 | false
249 | 0
250 | true
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
--------------------------------------------------------------------------------
/tests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ulimit -c unlimited
4 |
5 | DIR=$(pwd)
6 | nginx_fname=$(ls -1 $DIR/install/*.tar.gz)
7 |
8 | [ -d install/tmp ] || mkdir install/tmp
9 | tar zxf $nginx_fname -C install/tmp
10 |
11 | folder="$(ls -1 $DIR/install/tmp | grep nginx)"
12 |
13 | export PATH=$DIR/install/tmp/$folder/sbin:$PATH
14 | export LD_LIBRARY_PATH=$DIR/install/tmp/$folder/lib
15 |
16 | export LUA_CPATH=$DIR/install/tmp/$folder/lib/lua/5.1/cjson.so
17 |
18 | ret=0
19 |
20 | for t in $(ls t/*.t)
21 | do
22 | echo "Tests : "$t
23 | prove $t
24 | if [ $? -ne 0 ]; then
25 | ret=$?
26 | exit $ret
27 | fi
28 | done
29 |
30 | rm -rf t/servroot
31 | rm -rf install/tmp
32 |
33 | exit $ret
--------------------------------------------------------------------------------
/zoo_ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZigzagAK/ngx_zookeeper_lua/363970de7c074b89a89781c9d42dfabc9a06da98/zoo_ui.png
--------------------------------------------------------------------------------