├── .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 | [![Build Status](https://travis-ci.org/ZigzagAK/ngx_zookeeper_lua.svg)](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 | ![UI](zoo_ui.png) 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 += ''; 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 --------------------------------------------------------------------------------