├── .gitignore ├── .gitmodules ├── .travis.yml ├── Jenkinsfile ├── LICENSE ├── Makefile ├── README.md ├── connpool.lua ├── debian ├── .gitignore ├── changelog ├── compat ├── control ├── copyright ├── docs ├── rules ├── source │ └── format └── tarantool-connpool.install ├── debug ├── bench.sh ├── master.lua └── master1.lua ├── rockspecs ├── connpool-1.1.1-1.rockspec └── connpool-scm-1.rockspec ├── rpm └── tarantool-connpool.spec ├── test.sh └── test ├── .gitignore ├── .tarantoolctl ├── api ├── all.result ├── all.test.lua ├── lua │ └── connpool.lua ├── master.lua ├── master1.lua ├── master2.lua ├── monitoring.result ├── monitoring.test.lua ├── node_down.result ├── node_down.test.lua ├── one.result ├── one.test.lua ├── suite.ini ├── zone_list.result └── zone_list.test.lua ├── box └── proxy.lua ├── callback ├── connect.result ├── connect.test.lua ├── disconnect.result ├── disconnect.test.lua ├── lua │ └── connpool.lua ├── master.lua ├── master1.lua ├── master2.lua └── suite.ini └── test-run.py /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.snap 3 | *.xlog 4 | *.log 5 | test/lib/*.pyc 6 | test/lib/*/*.pyc 7 | test/var 8 | VERSION 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test-run"] 2 | path = test-run 3 | url = https://github.com/tarantool/test-run.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | services: 3 | - docker 4 | 5 | language: c 6 | compiler: gcc 7 | 8 | cache: 9 | directories: 10 | - $HOME/.cache 11 | 12 | env: 13 | global: 14 | - PRODUCT=tarantool-connpool 15 | matrix: 16 | - TARGET=test 17 | - OS=el DIST=6 18 | - OS=el DIST=7 19 | - OS=fedora DIST=24 20 | - OS=fedora DIST=25 21 | - OS=ubuntu DIST=precise 22 | - OS=ubuntu DIST=trusty 23 | - OS=ubuntu DIST=xenial 24 | - OS=ubuntu DIST=yakkety 25 | - OS=debian DIST=wheezy 26 | - OS=debian DIST=jessie 27 | - OS=debian DIST=stretch 28 | 29 | matrix: 30 | allow_failures: 31 | # - env: OS=el DIST=6 32 | # - env: OS=el DIST=7 33 | # - env: OS=fedora DIST=24 34 | # - env: OS=fedora DIST=25 35 | # - env: OS=ubuntu DIST=precise 36 | # - env: OS=ubuntu DIST=trusty 37 | # - env: OS=ubuntu DIST=xenial 38 | # - env: OS=ubuntu DIST=yakkety 39 | # - env: OS=debian DIST=wheezy 40 | # - env: OS=debian DIST=jessie 41 | # - env: OS=debian DIST=stretch 42 | 43 | script: 44 | - git describe --long 45 | - | 46 | if [ "${TARGET}" = "test" ]; then 47 | ./test.sh; 48 | else 49 | git clone https://github.com/packpack/packpack.git packpack; 50 | packpack/packpack; 51 | fi; 52 | 53 | before_deploy: 54 | - ls -l build/ 55 | 56 | deploy: 57 | # Deploy packages to PackageCloud 58 | - provider: packagecloud 59 | username: tarantool 60 | repository: "1_6" 61 | token: ${PACKAGECLOUD_TOKEN} 62 | dist: ${OS}/${DIST} 63 | package_glob: build/*.{rpm,deb} 64 | skip_cleanup: true 65 | on: 66 | branch: master 67 | condition: -n "${OS}" && -n "${DIST}" && -n "${PACKAGECLOUD_TOKEN}" 68 | - provider: packagecloud 69 | username: tarantool 70 | repository: "1_7" 71 | token: ${PACKAGECLOUD_TOKEN} 72 | dist: ${OS}/${DIST} 73 | package_glob: build/*.{rpm,deb} 74 | skip_cleanup: true 75 | on: 76 | branch: master 77 | condition: -n "${OS}" && -n "${DIST}" && -n "${PACKAGECLOUD_TOKEN}" 78 | - provider: packagecloud 79 | username: tarantool 80 | repository: "1_8" 81 | token: ${PACKAGECLOUD_TOKEN} 82 | dist: ${OS}/${DIST} 83 | package_glob: build/*.{rpm,deb} 84 | skip_cleanup: true 85 | on: 86 | branch: master 87 | condition: -n "${OS}" && -n "${DIST}" && -n "${PACKAGECLOUD_TOKEN}" 88 | 89 | notifications: 90 | email: 91 | recipients: 92 | - build@tarantool.org 93 | on_success: change 94 | on_failure: always 95 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | stage('Build'){ 2 | packpack = new org.tarantool.packpack() 3 | node { 4 | checkout scm 5 | packpack.prepareSources() 6 | } 7 | packpack.packpackBuildMatrix('result') 8 | } 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015-2016 Tarantool AUTHORS: 2 | please see AUTHORS file in tarantool/tarantool repository. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @echo "Usage: make test or make test-force" 3 | 4 | test: 5 | cd test/ && /usr/bin/python test-run.py 6 | 7 | test-force: 8 | cd test/ && /usr/bin/python test-run.py --force 9 | 10 | .PHONY: all test test-force 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Connection pool 2 | [![Build Status](https://travis-ci.org/tarantool/connection-pool.svg?branch=master)](https://travis-ci.org/tarantool/connection-pool) 3 | 4 | Lua connection pool for tarantool net.box with network zones support. 5 | 6 | ## API 7 | * `pool:init(cfg)` - init connection pool with given config 8 | * `pool:one(zone_id)` - returns random active connection from given zone(can be nil) 9 | * `pool:all(zone_id)` - returns all active connections from given zone(can be nil) 10 | * `pool:zone_list()` - returns list of network zones ids 11 | * `pool:get_heartbeat()` - returns monitoring state 12 | 13 | if `zone_id` is nil - return connections from all zones 14 | 15 | ## Available callbacks 16 | * `on_connected` - all nodes connected 17 | * `on_connected_one` - one node connected 18 | * `on_disconnect` - lost all connations in pool 19 | * `on_disconnect_one` - one node disconnect 20 | * `on_disconnect_zone` - all nodes in zone disconnected 21 | * `on_connfail` - monitoring detected connection problem 22 | * `on_init` - init complete, monitoring fibers started 23 | 24 | ## Configuration 25 | global: 26 | * `pool_name` - connection pool id 27 | * `monitor` - enable connection monitoring(by default `true`) 28 | * `servers` - table with servers settings 29 | 30 | servers: 31 | * `uri` - server uri with port 32 | * `login` 33 | * `password` 34 | * `zone` - network zone(can be nil) 35 | 36 | ## Example 37 | ```lua 38 | p = require('connpool') 39 | 40 | -- create new pool 41 | pool = p.new() 42 | -- set callback 43 | pool.on_connected = function(self) 44 | log.info('hello world') 45 | end 46 | 47 | -- config with 2 nodes in 2 zones and monitoring 48 | local cfg = { 49 | pool_name = 'mypool'; 50 | servers = { 51 | { 52 | uri = 'localhost:3313', login = 'tester', 53 | password = 'pass', zone = 'myzone1' 54 | }; 55 | { 56 | uri = 'localhost:3314', login = 'tester', 57 | password = 'pass', zone = 'myzone2' 58 | }; 59 | }; 60 | monitor = true; 61 | } 62 | 63 | -- start 64 | pool:init(cfg) 65 | ``` 66 | if there is no zone specified - all servers are in single zone 67 | -------------------------------------------------------------------------------- /connpool.lua: -------------------------------------------------------------------------------- 1 | local fiber = require('fiber') 2 | local log = require('log') 3 | local msgpack = require('msgpack') 4 | local remote = require('net.box') 5 | local yaml = require('yaml') 6 | 7 | -- default values 8 | local HEARTBEAT_TIMEOUT = 500 9 | local DEAD_TIMEOUT = 10 10 | local INFINITY_MIN = -1 11 | local RECONNECT_AFTER = msgpack.NULL 12 | 13 | local pool_table = {} 14 | 15 | -- intentionally made global. this needs to be redone 16 | -- heartbeat monitoring function 17 | function heartbeat(pool_id) 18 | log.debug('ping to %s', pool_id) 19 | return pool_table[pool_id] 20 | end 21 | 22 | -- default callbacks 23 | local function on_connfail(self, srv) 24 | log.info('%s connection failed', srv.uri) 25 | end 26 | 27 | local function on_connected_one(self, srv) 28 | log.info(' - %s - connected', srv.uri) 29 | end 30 | 31 | local function on_connected(self) 32 | log.info('connected to all servers') 33 | end 34 | 35 | local function on_disconnect_one(self, srv) 36 | log.info("kill %s by dead timeout", srv.uri) 37 | end 38 | 39 | local function on_disconnect_zone(self, name) 40 | log.info("zone %s has no active connections", name) 41 | end 42 | 43 | local function on_disconnect(self) 44 | log.info("there is no active connections") 45 | end 46 | 47 | local function on_init(self) 48 | log.info('started') 49 | end 50 | 51 | 52 | local function server_is_ok(self, srv, dead) 53 | if srv.ignore then 54 | return false 55 | end 56 | 57 | if dead then 58 | return true 59 | end 60 | 61 | if srv.conn == nil then 62 | return false 63 | end 64 | 65 | return srv.conn:is_connected() 66 | end 67 | 68 | local function merge_zones(self) 69 | local all_zones = {} 70 | local i = 1 71 | for _, zone in pairs(self.servers) do 72 | for _, server in pairs(zone.list) do 73 | all_zones[i] = server 74 | i = i + 1 75 | end 76 | end 77 | return all_zones 78 | end 79 | 80 | local function all(self, zone_id, include_dead) 81 | local res = {} 82 | local k = 1 83 | local zone 84 | 85 | if zone_id ~= nil then 86 | zone = self.servers[zone_id] 87 | else 88 | zone = { list=self:merge_zones() } 89 | end 90 | 91 | for _, srv in pairs(zone.list) do 92 | if self:server_is_ok(srv, include_dead) then 93 | res[k] = srv 94 | k = k + 1 95 | end 96 | end 97 | return res 98 | end 99 | 100 | local function one(self, zone_id, include_dead) 101 | local active_list = self:all(zone_id, include_dead) 102 | return active_list[math.random(#active_list)] 103 | end 104 | 105 | local function zone_list(self) 106 | local names = {} 107 | local i = 1 108 | for z_name, _ in pairs(self.servers) do 109 | names[i] = z_name 110 | i = i + 1 111 | end 112 | return names 113 | end 114 | 115 | local function _on_disconnect(self, srv) 116 | self:on_disconnect_one(srv) 117 | 118 | -- check zone and pool 119 | local d = 0 120 | local all_zones = self:zone_list() 121 | for _, name in pairs(all_zones) do 122 | local alive = self:all(name) 123 | if #alive == 0 then 124 | self:on_disconnect_zone(name) 125 | d = d + 1 126 | end 127 | end 128 | if d == #all_zones then 129 | self:on_disconnect() 130 | end 131 | end 132 | 133 | local function monitor_fiber(self) 134 | fiber.name("monitor") 135 | local i = 0 136 | while true do 137 | i = i + 1 138 | local server = self:one(nil, true) 139 | 140 | if server ~= nil then 141 | local uri = server.uri 142 | local dead = false 143 | for k, v in pairs(self.heartbeat_state) do 144 | -- true only if there is stuff in heartbeat_state 145 | if k ~= uri then 146 | dead = true 147 | log.debug("monitoring: %s", uri) 148 | break 149 | end 150 | end 151 | for k, v in pairs(self.heartbeat_state) do 152 | -- kill only if DEAD_TIMEOUT become in all servers 153 | if k ~= uri and (v[uri] == nil or v[uri].try < self.DEAD_TIMEOUT) then 154 | log.debug("%s is alive", uri) 155 | dead = false 156 | break 157 | end 158 | end 159 | 160 | if dead then 161 | server.conn:close() 162 | server.conn = nil 163 | self.epoch_counter = self.epoch_counter + 1 164 | _on_disconnect(self, server) 165 | end 166 | end 167 | fiber.sleep(math.random(100)/1000) 168 | end 169 | end 170 | 171 | -- merge node response data with local table by fiber time 172 | local function merge_tables(self, response) 173 | if response == nil then 174 | return 175 | end 176 | for seen_by_uri, node_data in pairs(self.heartbeat_state) do 177 | local node_table = response[seen_by_uri] 178 | if node_table ~= nil then 179 | for uri, data in pairs(node_table) do 180 | if data.ts > node_data[uri].ts then 181 | log.debug('merged heartbeat from ' .. seen_by_uri .. ' with ' .. uri) 182 | node_data[uri] = data 183 | end 184 | end 185 | end 186 | end 187 | end 188 | 189 | local function monitor_fail(self, uri) 190 | for _, zone in pairs(self.servers) do 191 | for _, server in pairs(zone.list) do 192 | if server.uri == uri then 193 | self:on_connfail(server) 194 | break 195 | end 196 | end 197 | end 198 | end 199 | 200 | -- heartbeat table and opinions management 201 | local function update_heartbeat(self, uri, response, status) 202 | -- set or update opinions and timestamp 203 | if self.self_server == nil then 204 | return 205 | end 206 | 207 | local opinion = self.heartbeat_state[self.self_server.uri] 208 | if not status then 209 | opinion[uri].try = opinion[uri].try + 1 210 | self:monitor_fail(uri) 211 | else 212 | opinion[uri].try = 0 213 | end 214 | opinion[uri].ts = fiber.time() 215 | -- update local heartbeat table 216 | self:merge_tables(response) 217 | end 218 | 219 | -- heartbeat worker 220 | local function heartbeat_fiber(self) 221 | fiber.name("heartbeat") 222 | local i = 0 223 | while true do 224 | i = i + 1 225 | -- random select node to check 226 | local server = self:one(nil, true) 227 | 228 | if server ~= nil then 229 | local uri = server.uri 230 | log.debug("checking %s", uri) 231 | 232 | if server.conn == nil then 233 | for _, opinion in pairs(self.heartbeat_state[server.uri]) do 234 | opinion.ts = fiber.time() 235 | opinion.try = INFINITY_MIN 236 | end 237 | 238 | if self.self_server then 239 | self.heartbeat_state[self.self_server.uri][server.uri] = { 240 | ts = fiber.time(), try = INFINITY_MIN} 241 | end 242 | else 243 | -- get heartbeat from node 244 | local response 245 | local status, err_state = pcall(function() 246 | local expr = "return heartbeat('" .. self.configuration.pool_name .. "')" 247 | response = server.conn:timeout(self.HEARTBEAT_TIMEOUT):eval(expr) 248 | end) 249 | -- update local heartbeat table 250 | self:update_heartbeat(uri, response, status) 251 | log.debug("%s", yaml.encode(self.heartbeat_state)) 252 | end 253 | end 254 | -- randomized wait for next check 255 | fiber.sleep(math.random(1000)/1000) 256 | end 257 | end 258 | 259 | -- function to check a connection after it's established 260 | local function check_connection(self, conn) 261 | return true 262 | end 263 | 264 | local function is_table_filled(self) 265 | local result = true 266 | for _, server in pairs(self.configuration.servers) do 267 | if self.heartbeat_state[server.uri] == nil then 268 | result = false 269 | break 270 | end 271 | for _, lserver in pairs(self.configuration.servers) do 272 | local srv = self.heartbeat_state[server.uri][lserver.uri] 273 | if srv == nil then 274 | result = false 275 | break 276 | end 277 | end 278 | end 279 | return result 280 | end 281 | 282 | local function wait_table_fill(self) 283 | while not self:is_table_filled() do 284 | fiber.sleep(0.01) 285 | end 286 | end 287 | 288 | local function fill_table(self) 289 | -- fill monitor table with start values 290 | for _, server in pairs(self.configuration.servers) do 291 | self.heartbeat_state[server.uri] = {} 292 | for _, lserver in pairs(self.configuration.servers) do 293 | self.heartbeat_state[server.uri][lserver.uri] = { 294 | try = 0, 295 | ts = INFINITY_MIN, 296 | } 297 | end 298 | end 299 | pool_table[self.configuration.pool_name] = self.heartbeat_state 300 | end 301 | 302 | local function get_heartbeat(self) 303 | return self.heartbeat_state 304 | end 305 | 306 | local function enable_operations(self) 307 | -- set helpers 308 | self.get_heartbeat = self.get_heartbeat 309 | end 310 | 311 | local function connect(self, id, server) 312 | local zone = self.servers[server.zone] 313 | log.info(' - %s - connecting...', server.uri) 314 | while true do 315 | local arbiter = server.arbiter or false 316 | local login = server.login 317 | local pass = server.password 318 | if login == nil or pass == nil then 319 | login = self.configuration.login 320 | pass = self.configuration.password 321 | end 322 | local uri = string.format("%s:%s@%s", login, pass, server.uri) 323 | local conn = remote:new(uri, { reconnect_after = self.RECONNECT_AFTER }) 324 | if conn:ping() and self:check_connection(conn) then 325 | local srv = { 326 | uri = server.uri, conn = conn, 327 | login = login, password=pass, 328 | id = id, arbiter = arbiter 329 | } 330 | zone.n = zone.n + 1 331 | zone.list[zone.n] = srv 332 | self:on_connected_one(srv) 333 | if conn:eval("return box.info.server.uuid") == box.info.server.uuid then 334 | self.self_server = srv 335 | end 336 | break 337 | end 338 | conn:close() 339 | log.warn(" - %s - server check failure", server.uri) 340 | fiber.sleep(1) 341 | end 342 | end 343 | 344 | local function connection_fiber(self) 345 | while true do 346 | for _, zone in pairs(self.servers) do 347 | for _, server in pairs(zone.list) do 348 | 349 | if server.conn == nil or not server.conn:is_connected() then 350 | server.conn = nil 351 | 352 | local uri = "" 353 | 354 | if server.password == "" then 355 | uri = string.format("%s@%s", server.login, server.uri) 356 | else 357 | uri = string.format("%s:%s@%s", server.login, server.password, server.uri) 358 | end 359 | 360 | local conn = remote:new(uri, { reconnect_after = self.RECONNECT_AFTER }) 361 | if conn:ping() and self:check_connection(conn) then 362 | server.conn = conn 363 | server.conn_error = "" 364 | log.debug("connected to: " .. server.uri) 365 | 366 | if conn:eval("return box.info.server.uuid") == box.info.server.uuid then 367 | log.info("setting self_server to " .. server.uri) 368 | self.self_server = server 369 | end 370 | else 371 | server.conn_error = conn.error 372 | end 373 | end 374 | end 375 | end 376 | fiber.sleep(1) 377 | end 378 | end 379 | 380 | -- connect with servers 381 | local function init(self, cfg) 382 | self.configuration = cfg 383 | -- check default pool name 384 | if self.configuration.pool_name == nil then 385 | self.configuration.pool_name = 'default' 386 | end 387 | log.info('establishing connection to cluster servers...') 388 | self.servers_n = 0 389 | self.zones_n = 0 390 | for id, server in pairs(cfg.servers) do 391 | self.servers_n = self.servers_n + 1 392 | local zone_name = server.zone 393 | if zone_name == nil then 394 | zone_name = 'default' 395 | end 396 | if self.servers[zone_name] == nil then 397 | self.zones_n = self.zones_n + 1 398 | self.servers[zone_name] = { id = self.zones_n, n = 0, list = {} } 399 | end 400 | local zone = self.servers[server.zone] 401 | 402 | local login = server.login 403 | local pass = server.password 404 | local arbiter = server.arbiter or false 405 | 406 | if login == nil or pass == nil then 407 | login = self.configuration.login 408 | pass = self.configuration.password 409 | end 410 | 411 | local srv = { 412 | uri = server.uri, conn = nil, 413 | login = login, password=pass, 414 | id = id, arbiter = arbiter 415 | } 416 | zone.n = zone.n + 1 417 | zone.list[zone.n] = srv 418 | end 419 | 420 | self:on_connected() 421 | self:fill_table() 422 | 423 | -- run monitoring and heartbeat fibers by default 424 | if cfg.monitor == nil or cfg.monitor then 425 | fiber.create(self.heartbeat_fiber, self) 426 | fiber.create(self.monitor_fiber, self) 427 | end 428 | fiber.create(self.connection_fiber, self) 429 | 430 | self:enable_operations() 431 | self.init_complete = true 432 | self:on_init() 433 | return true 434 | end 435 | 436 | local function len(self) 437 | return self.servers_n 438 | end 439 | 440 | local function is_connected(self) 441 | return self.init_complete 442 | end 443 | 444 | local function wait_connection(self) 445 | while not self:is_connected() do 446 | fiber.sleep(0.01) 447 | end 448 | end 449 | 450 | local function get_epoch(self) 451 | return self.epoch_counter 452 | end 453 | 454 | local function wait_epoch(self, epoch) 455 | while self:get_epoch() < epoch do 456 | fiber.sleep(0.01) 457 | end 458 | end 459 | 460 | local pool_object_methods = { 461 | server_is_ok = server_is_ok, 462 | merge_zones = merge_zones, 463 | merge_tables = merge_tables, 464 | monitor_fail = monitor_fail, 465 | update_heartbeat = update_heartbeat, 466 | connect = connect, 467 | fill_table = fill_table, 468 | enable_operations = enable_operations, 469 | check_connection = check_connection, 470 | 471 | len = len, 472 | is_connected = is_connected, 473 | wait_connection = wait_connection, 474 | get_epoch = get_epoch, 475 | wait_epoch = wait_epoch, 476 | is_table_filled = is_table_filled, 477 | wait_table_fill = wait_table_fill, 478 | 479 | -- public API 480 | init = init, 481 | one = one, 482 | all = all, 483 | zone_list = zone_list, 484 | get_heartbeat = get_heartbeat, 485 | } 486 | 487 | local function new() 488 | return setmetatable({ 489 | servers = {}, 490 | servers_n = 0, 491 | zones_n = 0, 492 | self_server = nil, 493 | heartbeat_state = {}, 494 | init_complete = false, 495 | epoch_counter = 1, 496 | configuration = {}, 497 | 498 | -- global constants 499 | HEARTBEAT_TIMEOUT = HEARTBEAT_TIMEOUT, 500 | DEAD_TIMEOUT = DEAD_TIMEOUT, 501 | RECONNECT_AFTER = RECONNECT_AFTER, 502 | 503 | -- background fibers 504 | monitor_fiber = monitor_fiber, 505 | heartbeat_fiber = heartbeat_fiber, 506 | connection_fiber = connection_fiber, 507 | 508 | -- callbacks available for set 509 | on_connected = on_connected, 510 | on_connected_one = on_connected_one, 511 | on_disconnect = on_disconnect, 512 | on_disconnect_one = on_disconnect_one, 513 | on_disconnect_zone = on_disconnect_zone, 514 | on_init = on_init, 515 | on_connfail = on_connfail, 516 | }, { 517 | __index = pool_object_methods 518 | }) 519 | end 520 | 521 | return { 522 | new = new 523 | } 524 | -- vim: ts=4:sw=4:sts=4:et 525 | -------------------------------------------------------------------------------- /debian/.gitignore: -------------------------------------------------------------------------------- 1 | tarantool-connpool/ 2 | files 3 | stamp-* 4 | *.substvars 5 | *.log 6 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | tarantool-connpool (1.1.0-1) unstable; urgency=medium 2 | 3 | * Initial release. 4 | 5 | -- Roman Tsisyk Fri, 19 Feb 2016 14:34:49 +0300 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: tarantool-connpool 2 | Priority: optional 3 | Section: database 4 | Maintainer: Roman Tsisyk 5 | Build-Depends: debhelper (>= 9), 6 | tarantool (>= 1.6.8.0) 7 | Standards-Version: 3.9.6 8 | Homepage: https://github.com/tarantool/connpool 9 | Vcs-Git: git://github.com/tarantool/connpool.git 10 | Vcs-Browser: https://github.com/tarantool/connpool 11 | 12 | Package: tarantool-connpool 13 | Architecture: all 14 | Depends: tarantool (>= 1.6.8.0), ${misc:Depends} 15 | Description: net.box connection pool for Tarantool 16 | Lua connection pool for tarantool net.box with network zones support. 17 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Debianized-By: Roman Tsisyk 3 | Upstream-Name: tarantool-connpool 4 | Upstream-Contact: support@tarantool.org 5 | Source: https://github.com/tarantool/connpool 6 | 7 | Files: * 8 | Copyright: 2015-2016 Tarantool AUTHORS 9 | License: BSD-2-Clause 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions 12 | are met: 13 | 1. Redistributions of source code must retain the above copyright 14 | notice, this list of conditions and the following disclaimer. 15 | 2. Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | . 19 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | %: 4 | dh $@ 5 | 6 | override_dh_auto_build: 7 | @true 8 | override_dh_auto_test: 9 | echo "Test are not implemented yet" 10 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/tarantool-connpool.install: -------------------------------------------------------------------------------- 1 | connpool.lua usr/share/tarantool/ 2 | -------------------------------------------------------------------------------- /debug/bench.sh: -------------------------------------------------------------------------------- 1 | killall tarantool 2 | rm *.snap 3 | rm *.log 4 | rm work/*.log 5 | rm work/*.snap 6 | 7 | tarantool master.lua & 8 | tarantool master1.lua & 9 | 10 | -------------------------------------------------------------------------------- /debug/master.lua: -------------------------------------------------------------------------------- 1 | lib_pool = require('connpool') 2 | log = require('log') 3 | yaml = require('yaml') 4 | pool = lib_pool.new() 5 | pool.on_connected = function() 6 | log.info('on_connect callback') 7 | end 8 | 9 | pool.on_init = function() 10 | log.info('on_init callback') 11 | end 12 | 13 | local cfg = { 14 | pool_name = 'mypool'; 15 | servers = { 16 | { 17 | uri = 'localhost:3313', login = 'tester', 18 | password = 'pass', zone = '0' 19 | }; 20 | { 21 | uri = 'localhost:3314', login = 'tester', 22 | password = 'pass', zone = '1' 23 | }; 24 | }; 25 | } 26 | 27 | box.cfg { 28 | slab_alloc_arena = 1.0; 29 | slab_alloc_factor = 1.06; 30 | slab_alloc_minimal = 16; 31 | wal_mode = 'none'; 32 | logger = 'm1.log'; 33 | log_level = 5; 34 | listen = 3313; 35 | } 36 | 37 | box.schema.user.create('tester', { password = 'pass' }) 38 | box.schema.user.grant('tester', 'read,write,execute', 'universe') 39 | 40 | -- init connections 41 | pool:init(cfg) 42 | 43 | -- wait for operations 44 | require('fiber').sleep(3) 45 | 46 | -- show results 47 | log.info('Len=%d', #pool:all()) 48 | log.info(yaml.encode(pool:get_heartbeat())) 49 | -------------------------------------------------------------------------------- /debug/master1.lua: -------------------------------------------------------------------------------- 1 | lib_pool = require('connpool') 2 | log = require('log') 3 | yaml = require('yaml') 4 | 5 | local cfg = { 6 | pool_name = 'mypool'; 7 | servers = { 8 | { 9 | uri = 'localhost:3313', login = 'tester', 10 | password = 'pass', zone = '0' 11 | }; 12 | { 13 | uri = 'localhost:3314', login = 'tester', 14 | password = 'pass', zone = '1' 15 | }; 16 | }; 17 | } 18 | 19 | box.cfg { 20 | slab_alloc_arena = 1.0; 21 | slab_alloc_factor = 1.06; 22 | slab_alloc_minimal = 16; 23 | wal_mode = 'none'; 24 | logger = 'm2.log'; 25 | work_dir = 'work'; 26 | log_level = 5; 27 | listen = 3314; 28 | } 29 | 30 | box.schema.user.create('tester', { password = 'pass' }) 31 | box.schema.user.grant('tester', 'read,write,execute', 'universe') 32 | 33 | pool = lib_pool.new() 34 | 35 | -- init connections 36 | pool:init(cfg) 37 | 38 | -- wait for operations 39 | require('fiber').sleep(3) 40 | 41 | -- show results 42 | log.info('Len=%d', #pool:all()) 43 | -------------------------------------------------------------------------------- /rockspecs/connpool-1.1.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = 'connpool' 2 | version = '1.1.1-1' 3 | source = { 4 | url = 'git+https://github.com/tarantool/connpool.git', 5 | tag = '1.1.1', 6 | } 7 | description = { 8 | summary = "Net box connection pool for Tarantool", 9 | homepage = 'https://github.com/tarantool/connpool.git', 10 | license = 'BSD', 11 | } 12 | dependencies = { 13 | 'lua >= 5.1' 14 | } 15 | build = { 16 | type = 'builtin', 17 | 18 | modules = { 19 | ['connpool'] = 'connpool.lua' 20 | } 21 | } 22 | 23 | -- vim: syntax=lua 24 | -------------------------------------------------------------------------------- /rockspecs/connpool-scm-1.rockspec: -------------------------------------------------------------------------------- 1 | package = 'connpool' 2 | version = 'scm-1' 3 | source = { 4 | url = 'git+https://github.com/tarantool/connpool.git', 5 | branch = 'master', 6 | } 7 | description = { 8 | summary = "Net box connection pool for Tarantool", 9 | homepage = 'https://github.com/tarantool/connpool.git', 10 | license = 'BSD', 11 | } 12 | dependencies = { 13 | 'lua >= 5.1' 14 | } 15 | build = { 16 | type = 'builtin', 17 | 18 | modules = { 19 | ['connpool'] = 'connpool.lua' 20 | } 21 | } 22 | 23 | -- vim: syntax=lua 24 | -------------------------------------------------------------------------------- /rpm/tarantool-connpool.spec: -------------------------------------------------------------------------------- 1 | Name: tarantool-connpool 2 | Version: 1.1.0 3 | Release: 1%{?dist} 4 | Summary: net.box connection pool for Tarantool 5 | Group: Applications/Databases 6 | License: BSD 7 | URL: https://github.com/tarantool/connpool 8 | Source0: https://github.com/tarantool/connpool/archive/%{version}/connpool-%{version}.tar.gz 9 | BuildArch: noarch 10 | BuildRequires: tarantool >= 1.6.8.0 11 | Requires: tarantool >= 1.6.8.0 12 | 13 | # For tests 14 | %if (0%{?fedora} >= 22) 15 | BuildRequires: python >= 2.7 16 | BuildRequires: python-six >= 1.9.0 17 | BuildRequires: python-gevent >= 1.0 18 | BuildRequires: python-yaml >= 3.0.9 19 | # Temporary for old test-run 20 | # https://github.com/tarantool/connpool/issues/1 21 | BuildRequires: python-daemon 22 | %endif 23 | 24 | %description 25 | Lua connection pool for tarantool net.box with network zones support. 26 | 27 | %prep 28 | %setup -q -n connpool-%{version} 29 | 30 | %check 31 | %if (0%{?fedora} >= 22) 32 | make test 33 | %endif 34 | 35 | %install 36 | install -d %{buildroot}%{_datarootdir}/tarantool/ 37 | install -m 0644 connpool.lua %{buildroot}%{_datarootdir}/tarantool/ 38 | 39 | %files 40 | %{_datarootdir}/tarantool/connpool.lua 41 | %doc README.md 42 | %{!?_licensedir:%global license %doc} 43 | %license LICENSE 44 | 45 | %changelog 46 | * Fri Feb 19 2016 Roman Tsisyk 1.1.0-1 47 | - Initial version of the RPM spec 48 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | curl -s https://packagecloud.io/install/repositories/tarantool/1_6/script.deb.sh | sudo bash 5 | sudo apt-get update > /dev/null 6 | sudo apt-get -q -y install tarantool tarantool-dev 7 | 8 | git submodule update --init --recursive 9 | pip install -r test-run/requirements.txt --user 10 | pip install git+https://github.com/tarantool/tarantool-python.git --user 11 | make test-force 12 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | *.reject 2 | -------------------------------------------------------------------------------- /test/.tarantoolctl: -------------------------------------------------------------------------------- 1 | -- Options for test-run tarantoolctl 2 | local workdir = os.getenv('TEST_WORKDIR') 3 | default_cfg = { 4 | pid_file = workdir, 5 | wal_dir = workdir, 6 | snap_dir = workdir, 7 | logger = workdir, 8 | background = false, 9 | } 10 | local ver = string.sub(require('tarantool').version, 1,3) 11 | if ver ~= '1.6' then 12 | default_cfg.vinyl_dir = workdir 13 | end 14 | 15 | instance_dir = workdir 16 | 17 | -- vim: set ft=lua : 18 | -------------------------------------------------------------------------------- /test/api/all.result: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | --- 3 | ... 4 | test_run = env.new() 5 | --- 6 | ... 7 | test_run:cmd("create server master1 with script='api/master1.lua', lua_libs='api/lua/connpool.lua'") 8 | --- 9 | - true 10 | ... 11 | test_run:cmd("create server master2 with script='api/master2.lua', lua_libs='api/lua/connpool.lua'") 12 | --- 13 | - true 14 | ... 15 | test_run:cmd("start server master1") 16 | --- 17 | - true 18 | ... 19 | test_run:cmd("start server master2") 20 | --- 21 | - true 22 | ... 23 | pool:wait_connection() 24 | --- 25 | ... 26 | pool:wait_table_fill() 27 | --- 28 | ... 29 | servers = pool:all() 30 | --- 31 | ... 32 | #servers 33 | --- 34 | - 3 35 | ... 36 | zone = pool:all('myzone1') 37 | --- 38 | ... 39 | #zone 40 | --- 41 | - 1 42 | ... 43 | _ = test_run:cmd("stop server master1") 44 | --- 45 | ... 46 | _ = test_run:cmd("stop server master2") 47 | --- 48 | ... 49 | test_run:cmd("cleanup server master1") 50 | --- 51 | - true 52 | ... 53 | test_run:cmd("cleanup server master2") 54 | --- 55 | - true 56 | ... 57 | test_run:cmd("restart server default with cleanup=1") 58 | -------------------------------------------------------------------------------- /test/api/all.test.lua: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | test_run = env.new() 3 | test_run:cmd("create server master1 with script='api/master1.lua', lua_libs='api/lua/connpool.lua'") 4 | test_run:cmd("create server master2 with script='api/master2.lua', lua_libs='api/lua/connpool.lua'") 5 | test_run:cmd("start server master1") 6 | test_run:cmd("start server master2") 7 | pool:wait_connection() 8 | pool:wait_table_fill() 9 | 10 | servers = pool:all() 11 | #servers 12 | 13 | zone = pool:all('myzone1') 14 | #zone 15 | 16 | _ = test_run:cmd("stop server master1") 17 | _ = test_run:cmd("stop server master2") 18 | test_run:cmd("cleanup server master1") 19 | test_run:cmd("cleanup server master2") 20 | test_run:cmd("restart server default with cleanup=1") 21 | -------------------------------------------------------------------------------- /test/api/lua/connpool.lua: -------------------------------------------------------------------------------- 1 | ../../../connpool.lua -------------------------------------------------------------------------------- /test/api/master.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tarantool 2 | lib_pool = require('connpool') 3 | os = require('os') 4 | fiber = require('fiber') 5 | 6 | local cfg = { 7 | pool_name = 'mypool'; 8 | servers = { 9 | { 10 | uri = 'localhost:33130', login = 'tester', 11 | password = 'pass', zone = 'myzone1' 12 | }; 13 | { 14 | uri = 'localhost:33131', login = 'tester', 15 | password = 'pass', zone = 'myzone2' 16 | }; 17 | { 18 | uri = 'localhost:33132', login = 'tester', 19 | password = 'pass', zone = 'myzone3' 20 | }; 21 | 22 | }; 23 | } 24 | 25 | box.cfg { 26 | slab_alloc_arena = 0.1; 27 | wal_mode = 'none'; 28 | listen = 33130; 29 | custom_proc_title = "master" 30 | } 31 | 32 | require('console').listen(os.getenv('ADMIN')) 33 | 34 | box.once("bootstrap", function() 35 | box.schema.user.create('tester', { password = 'pass'}) 36 | box.schema.user.grant('tester', 'read,write,execute', 'universe') 37 | end) 38 | 39 | pool = lib_pool.new() 40 | 41 | -- init 42 | fiber.create(function() 43 | pool:init(cfg) 44 | end) 45 | -------------------------------------------------------------------------------- /test/api/master1.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tarantool 2 | lib_pool = require('connpool') 3 | os = require('os') 4 | fiber = require('fiber') 5 | 6 | local cfg = { 7 | pool_name = 'mypool'; 8 | servers = { 9 | { 10 | uri = 'localhost:33130', login = 'tester', 11 | password = 'pass', zone = 'myzone1' 12 | }; 13 | { 14 | uri = 'localhost:33131', login = 'tester', 15 | password = 'pass', zone = 'myzone2' 16 | }; 17 | { 18 | uri = 'localhost:33132', login = 'tester', 19 | password = 'pass', zone = 'myzone3' 20 | }; 21 | 22 | }; 23 | } 24 | 25 | box.cfg { 26 | slab_alloc_arena = 0.1; 27 | wal_mode = 'none'; 28 | listen = 33131; 29 | custom_proc_title = "master1" 30 | } 31 | 32 | require('console').listen(os.getenv('ADMIN')) 33 | 34 | box.once("bootstrap", function() 35 | box.schema.user.create('tester', { password = 'pass'}) 36 | box.schema.user.grant('tester', 'read,write,execute', 'universe') 37 | end) 38 | 39 | pool = lib_pool.new() 40 | 41 | -- init 42 | fiber.create(function() 43 | pool:init(cfg) 44 | end) 45 | -------------------------------------------------------------------------------- /test/api/master2.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tarantool 2 | lib_pool = require('connpool') 3 | os = require('os') 4 | fiber = require('fiber') 5 | 6 | local cfg = { 7 | pool_name = 'mypool'; 8 | servers = { 9 | { 10 | uri = 'localhost:33130', login = 'tester', 11 | password = 'pass', zone = 'myzone1' 12 | }; 13 | { 14 | uri = 'localhost:33131', login = 'tester', 15 | password = 'pass', zone = 'myzone2' 16 | }; 17 | { 18 | uri = 'localhost:33132', login = 'tester', 19 | password = 'pass', zone = 'myzone3' 20 | }; 21 | }; 22 | } 23 | 24 | box.cfg { 25 | slab_alloc_arena = 0.1; 26 | wal_mode = 'none'; 27 | listen = 33132; 28 | custom_proc_title = "master2" 29 | } 30 | 31 | require('console').listen(os.getenv('ADMIN')) 32 | 33 | box.once("bootstrap", function() 34 | box.schema.user.create('tester', { password = 'pass'}) 35 | box.schema.user.grant('tester', 'read,write,execute', 'universe') 36 | end) 37 | 38 | pool = lib_pool.new() 39 | 40 | -- init 41 | fiber.create(function() 42 | pool:init(cfg) 43 | end) 44 | -------------------------------------------------------------------------------- /test/api/monitoring.result: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | --- 3 | ... 4 | test_run = env.new() 5 | --- 6 | ... 7 | test_run:cmd("create server master1 with script='api/master1.lua', lua_libs='api/lua/connpool.lua'") 8 | --- 9 | - true 10 | ... 11 | test_run:cmd("create server master2 with script='api/master2.lua', lua_libs='api/lua/connpool.lua'") 12 | --- 13 | - true 14 | ... 15 | test_run:cmd("start server master1") 16 | --- 17 | - true 18 | ... 19 | test_run:cmd("start server master2") 20 | --- 21 | - true 22 | ... 23 | pool:wait_connection() 24 | --- 25 | ... 26 | -- monitoring test 27 | pool:wait_table_fill() 28 | --- 29 | ... 30 | pool:is_table_filled() 31 | --- 32 | - true 33 | ... 34 | test_run:cmd("switch master1") 35 | --- 36 | - true 37 | ... 38 | pool:wait_table_fill() 39 | --- 40 | ... 41 | pool:is_table_filled() 42 | --- 43 | - true 44 | ... 45 | test_run:cmd("switch default") 46 | --- 47 | - true 48 | ... 49 | _ = test_run:cmd("stop server master1") 50 | --- 51 | ... 52 | _ = test_run:cmd("stop server master2") 53 | --- 54 | ... 55 | test_run:cmd("cleanup server master1") 56 | --- 57 | - true 58 | ... 59 | test_run:cmd("cleanup server master2") 60 | --- 61 | - true 62 | ... 63 | test_run:cmd("restart server default with cleanup=1") 64 | -------------------------------------------------------------------------------- /test/api/monitoring.test.lua: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | test_run = env.new() 3 | test_run:cmd("create server master1 with script='api/master1.lua', lua_libs='api/lua/connpool.lua'") 4 | test_run:cmd("create server master2 with script='api/master2.lua', lua_libs='api/lua/connpool.lua'") 5 | test_run:cmd("start server master1") 6 | test_run:cmd("start server master2") 7 | pool:wait_connection() 8 | 9 | -- monitoring test 10 | pool:wait_table_fill() 11 | pool:is_table_filled() 12 | 13 | test_run:cmd("switch master1") 14 | pool:wait_table_fill() 15 | pool:is_table_filled() 16 | 17 | test_run:cmd("switch default") 18 | 19 | _ = test_run:cmd("stop server master1") 20 | _ = test_run:cmd("stop server master2") 21 | test_run:cmd("cleanup server master1") 22 | test_run:cmd("cleanup server master2") 23 | test_run:cmd("restart server default with cleanup=1") 24 | -------------------------------------------------------------------------------- /test/api/node_down.result: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | --- 3 | ... 4 | test_run = env.new() 5 | --- 6 | ... 7 | test_run:cmd("create server master1 with script='api/master1.lua', lua_libs='api/lua/connpool.lua'") 8 | --- 9 | - true 10 | ... 11 | test_run:cmd("create server master2 with script='api/master2.lua', lua_libs='api/lua/connpool.lua'") 12 | --- 13 | - true 14 | ... 15 | test_run:cmd("start server master1") 16 | --- 17 | - true 18 | ... 19 | test_run:cmd("start server master2") 20 | --- 21 | - true 22 | ... 23 | pool:wait_connection() 24 | --- 25 | ... 26 | --shard.wait_epoch(3) 27 | pool:wait_table_fill() 28 | --- 29 | ... 30 | pool:is_table_filled() 31 | --- 32 | - true 33 | ... 34 | test_run:cmd("switch master1") 35 | --- 36 | - true 37 | ... 38 | pool:wait_table_fill() 39 | --- 40 | ... 41 | pool:is_table_filled() 42 | --- 43 | - true 44 | ... 45 | test_run:cmd("switch master2") 46 | --- 47 | - true 48 | ... 49 | pool:wait_table_fill() 50 | --- 51 | ... 52 | pool:is_table_filled() 53 | --- 54 | - true 55 | ... 56 | test_run:cmd("switch default") 57 | --- 58 | - true 59 | ... 60 | servers = pool:all() 61 | --- 62 | ... 63 | #servers 64 | --- 65 | - 3 66 | ... 67 | -- Kill server and wait for monitoring fibers kill 68 | _ = test_run:cmd("stop server master1") 69 | --- 70 | ... 71 | -- Check that node is removed from shard 72 | pool:wait_epoch(2) 73 | --- 74 | ... 75 | pool:is_table_filled() 76 | --- 77 | - false 78 | ... 79 | test_run:cmd("switch master2") 80 | --- 81 | - true 82 | ... 83 | pool:wait_epoch(2) 84 | --- 85 | ... 86 | pool:is_table_filled() 87 | --- 88 | - false 89 | ... 90 | test_run:cmd("switch default") 91 | --- 92 | - true 93 | ... 94 | servers = pool:all() 95 | --- 96 | ... 97 | #servers 98 | --- 99 | - 2 100 | ... 101 | _ = test_run:cmd("stop server master2") 102 | --- 103 | ... 104 | test_run:cmd("cleanup server master1") 105 | --- 106 | - true 107 | ... 108 | test_run:cmd("cleanup server master2") 109 | --- 110 | - true 111 | ... 112 | test_run:cmd("restart server default with cleanup=1") 113 | -------------------------------------------------------------------------------- /test/api/node_down.test.lua: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | test_run = env.new() 3 | test_run:cmd("create server master1 with script='api/master1.lua', lua_libs='api/lua/connpool.lua'") 4 | test_run:cmd("create server master2 with script='api/master2.lua', lua_libs='api/lua/connpool.lua'") 5 | test_run:cmd("start server master1") 6 | test_run:cmd("start server master2") 7 | pool:wait_connection() 8 | --shard.wait_epoch(3) 9 | pool:wait_table_fill() 10 | pool:is_table_filled() 11 | 12 | test_run:cmd("switch master1") 13 | pool:wait_table_fill() 14 | pool:is_table_filled() 15 | 16 | test_run:cmd("switch master2") 17 | pool:wait_table_fill() 18 | pool:is_table_filled() 19 | 20 | test_run:cmd("switch default") 21 | 22 | servers = pool:all() 23 | #servers 24 | 25 | -- Kill server and wait for monitoring fibers kill 26 | _ = test_run:cmd("stop server master1") 27 | 28 | -- Check that node is removed from shard 29 | pool:wait_epoch(2) 30 | pool:is_table_filled() 31 | 32 | test_run:cmd("switch master2") 33 | pool:wait_epoch(2) 34 | pool:is_table_filled() 35 | test_run:cmd("switch default") 36 | 37 | servers = pool:all() 38 | #servers 39 | 40 | _ = test_run:cmd("stop server master2") 41 | test_run:cmd("cleanup server master1") 42 | test_run:cmd("cleanup server master2") 43 | test_run:cmd("restart server default with cleanup=1") 44 | -------------------------------------------------------------------------------- /test/api/one.result: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | --- 3 | ... 4 | test_run = env.new() 5 | --- 6 | ... 7 | test_run:cmd("create server master1 with script='api/master1.lua', lua_libs='api/lua/connpool.lua'") 8 | --- 9 | - true 10 | ... 11 | test_run:cmd("create server master2 with script='api/master2.lua', lua_libs='api/lua/connpool.lua'") 12 | --- 13 | - true 14 | ... 15 | test_run:cmd("start server master1") 16 | --- 17 | - true 18 | ... 19 | test_run:cmd("start server master2") 20 | --- 21 | - true 22 | ... 23 | pool:wait_connection() 24 | --- 25 | ... 26 | pool:wait_table_fill() 27 | --- 28 | ... 29 | server = pool:one() 30 | --- 31 | ... 32 | type(server) 33 | --- 34 | - table 35 | ... 36 | type(server.conn) 37 | --- 38 | - table 39 | ... 40 | from_zone = pool:one('myzone1') 41 | --- 42 | ... 43 | from_zone.uri 44 | --- 45 | - localhost:33130 46 | ... 47 | _ = test_run:cmd("stop server master1") 48 | --- 49 | ... 50 | _ = test_run:cmd("stop server master2") 51 | --- 52 | ... 53 | test_run:cmd("cleanup server master1") 54 | --- 55 | - true 56 | ... 57 | test_run:cmd("cleanup server master2") 58 | --- 59 | - true 60 | ... 61 | test_run:cmd("restart server default with cleanup=1") 62 | -------------------------------------------------------------------------------- /test/api/one.test.lua: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | test_run = env.new() 3 | test_run:cmd("create server master1 with script='api/master1.lua', lua_libs='api/lua/connpool.lua'") 4 | test_run:cmd("create server master2 with script='api/master2.lua', lua_libs='api/lua/connpool.lua'") 5 | test_run:cmd("start server master1") 6 | test_run:cmd("start server master2") 7 | pool:wait_connection() 8 | pool:wait_table_fill() 9 | 10 | server = pool:one() 11 | type(server) 12 | type(server.conn) 13 | 14 | from_zone = pool:one('myzone1') 15 | from_zone.uri 16 | 17 | _ = test_run:cmd("stop server master1") 18 | _ = test_run:cmd("stop server master2") 19 | test_run:cmd("cleanup server master1") 20 | test_run:cmd("cleanup server master2") 21 | test_run:cmd("restart server default with cleanup=1") 22 | -------------------------------------------------------------------------------- /test/api/suite.ini: -------------------------------------------------------------------------------- 1 | [default] 2 | core = tarantool 3 | description = connection pool api tests 4 | script = master.lua 5 | lua_libs = lua/connpool.lua 6 | -------------------------------------------------------------------------------- /test/api/zone_list.result: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | --- 3 | ... 4 | test_run = env.new() 5 | --- 6 | ... 7 | test_run:cmd("create server master1 with script='api/master1.lua', lua_libs='api/lua/connpool.lua'") 8 | --- 9 | - true 10 | ... 11 | test_run:cmd("create server master2 with script='api/master2.lua', lua_libs='api/lua/connpool.lua'") 12 | --- 13 | - true 14 | ... 15 | test_run:cmd("start server master1") 16 | --- 17 | - true 18 | ... 19 | test_run:cmd("start server master2") 20 | --- 21 | - true 22 | ... 23 | pool:wait_connection() 24 | --- 25 | ... 26 | pool:wait_table_fill() 27 | --- 28 | ... 29 | pool:zone_list() 30 | --- 31 | - - myzone1 32 | - myzone3 33 | - myzone2 34 | ... 35 | _ = test_run:cmd("stop server master1") 36 | --- 37 | ... 38 | _ = test_run:cmd("stop server master2") 39 | --- 40 | ... 41 | test_run:cmd("cleanup server master1") 42 | --- 43 | - true 44 | ... 45 | test_run:cmd("cleanup server master2") 46 | --- 47 | - true 48 | ... 49 | test_run:cmd("restart server default with cleanup=1") 50 | -------------------------------------------------------------------------------- /test/api/zone_list.test.lua: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | test_run = env.new() 3 | test_run:cmd("create server master1 with script='api/master1.lua', lua_libs='api/lua/connpool.lua'") 4 | test_run:cmd("create server master2 with script='api/master2.lua', lua_libs='api/lua/connpool.lua'") 5 | test_run:cmd("start server master1") 6 | test_run:cmd("start server master2") 7 | pool:wait_connection() 8 | pool:wait_table_fill() 9 | 10 | pool:zone_list() 11 | 12 | _ = test_run:cmd("stop server master1") 13 | _ = test_run:cmd("stop server master2") 14 | test_run:cmd("cleanup server master1") 15 | test_run:cmd("cleanup server master2") 16 | test_run:cmd("restart server default with cleanup=1") 17 | -------------------------------------------------------------------------------- /test/box/proxy.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tarantool 2 | os = require('os') 3 | 4 | box.cfg{ 5 | listen = os.getenv("LISTEN"), 6 | slab_alloc_arena = 0.1, 7 | pid_file = "tarantool.pid", 8 | rows_per_wal = 50 9 | } 10 | 11 | require('console').listen(os.getenv('ADMIN')) 12 | -------------------------------------------------------------------------------- /test/callback/connect.result: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | --- 3 | ... 4 | test_run = env.new() 5 | --- 6 | ... 7 | test_run:cmd("create server master1 with script='callback/master1.lua', lua_libs='callback/lua/connpool.lua'") 8 | --- 9 | - true 10 | ... 11 | test_run:cmd("create server master2 with script='callback/master2.lua', lua_libs='callback/lua/connpool.lua'") 12 | --- 13 | - true 14 | ... 15 | test_run:cmd("start server master1") 16 | --- 17 | - true 18 | ... 19 | test_run:cmd("start server master2") 20 | --- 21 | - true 22 | ... 23 | pool:wait_connection() 24 | --- 25 | ... 26 | pool:wait_table_fill() 27 | --- 28 | ... 29 | results 30 | --- 31 | - - server connected 32 | - server connected 33 | - server connected 34 | - all nodes connected 35 | - init complete 36 | ... 37 | _ = test_run:cmd("stop server master1") 38 | --- 39 | ... 40 | _ = test_run:cmd("stop server master2") 41 | --- 42 | ... 43 | test_run:cmd("cleanup server master1") 44 | --- 45 | - true 46 | ... 47 | test_run:cmd("cleanup server master2") 48 | --- 49 | - true 50 | ... 51 | test_run:cmd("restart server default with cleanup=1") 52 | -------------------------------------------------------------------------------- /test/callback/connect.test.lua: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | test_run = env.new() 3 | test_run:cmd("create server master1 with script='callback/master1.lua', lua_libs='callback/lua/connpool.lua'") 4 | test_run:cmd("create server master2 with script='callback/master2.lua', lua_libs='callback/lua/connpool.lua'") 5 | test_run:cmd("start server master1") 6 | test_run:cmd("start server master2") 7 | 8 | pool:wait_connection() 9 | pool:wait_table_fill() 10 | results 11 | 12 | _ = test_run:cmd("stop server master1") 13 | _ = test_run:cmd("stop server master2") 14 | test_run:cmd("cleanup server master1") 15 | test_run:cmd("cleanup server master2") 16 | test_run:cmd("restart server default with cleanup=1") 17 | -------------------------------------------------------------------------------- /test/callback/disconnect.result: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | --- 3 | ... 4 | test_run = env.new() 5 | --- 6 | ... 7 | test_run:cmd("create server master1 with script='callback/master1.lua', lua_libs='callback/lua/connpool.lua'") 8 | --- 9 | - true 10 | ... 11 | test_run:cmd("create server master2 with script='callback/master2.lua', lua_libs='callback/lua/connpool.lua'") 12 | --- 13 | - true 14 | ... 15 | test_run:cmd("start server master1") 16 | --- 17 | - true 18 | ... 19 | test_run:cmd("start server master2") 20 | --- 21 | - true 22 | ... 23 | pool:wait_connection() 24 | --- 25 | ... 26 | pool:wait_table_fill() 27 | --- 28 | ... 29 | _ = test_run:cmd("stop server master1") 30 | --- 31 | ... 32 | pool:wait_epoch(2) 33 | --- 34 | ... 35 | d_results 36 | --- 37 | - - server disconnected 38 | - zone myzone2 disconnected 39 | ... 40 | fails >= pool.DEAD_TIMEOUT 41 | --- 42 | - true 43 | ... 44 | _ = test_run:cmd("stop server master2") 45 | --- 46 | ... 47 | test_run:cmd("cleanup server master1") 48 | --- 49 | - true 50 | ... 51 | test_run:cmd("cleanup server master2") 52 | --- 53 | - true 54 | ... 55 | test_run:cmd("restart server default with cleanup=1") 56 | -------------------------------------------------------------------------------- /test/callback/disconnect.test.lua: -------------------------------------------------------------------------------- 1 | env = require('test_run') 2 | test_run = env.new() 3 | test_run:cmd("create server master1 with script='callback/master1.lua', lua_libs='callback/lua/connpool.lua'") 4 | test_run:cmd("create server master2 with script='callback/master2.lua', lua_libs='callback/lua/connpool.lua'") 5 | test_run:cmd("start server master1") 6 | test_run:cmd("start server master2") 7 | 8 | pool:wait_connection() 9 | pool:wait_table_fill() 10 | 11 | _ = test_run:cmd("stop server master1") 12 | 13 | pool:wait_epoch(2) 14 | d_results 15 | fails >= pool.DEAD_TIMEOUT 16 | 17 | _ = test_run:cmd("stop server master2") 18 | test_run:cmd("cleanup server master1") 19 | test_run:cmd("cleanup server master2") 20 | test_run:cmd("restart server default with cleanup=1") 21 | -------------------------------------------------------------------------------- /test/callback/lua/connpool.lua: -------------------------------------------------------------------------------- 1 | ../../../connpool.lua -------------------------------------------------------------------------------- /test/callback/master.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tarantool 2 | lib_pool = require('connpool') 3 | log = require('log') 4 | os = require('os') 5 | fiber = require('fiber') 6 | 7 | local cfg = { 8 | pool_name = 'mypool'; 9 | servers = { 10 | { 11 | uri = 'localhost:33130', login = 'tester', 12 | password = 'pass', zone = 'myzone1' 13 | }; 14 | { 15 | uri = 'localhost:33131', login = 'tester', 16 | password = 'pass', zone = 'myzone2' 17 | }; 18 | { 19 | uri = 'localhost:33132', login = 'tester', 20 | password = 'pass', zone = 'myzone3' 21 | }; 22 | 23 | }; 24 | } 25 | 26 | box.cfg { 27 | slab_alloc_arena = 0.1; 28 | wal_mode = 'none'; 29 | listen = 33130; 30 | custom_proc_title = "master" 31 | } 32 | 33 | require('console').listen(os.getenv('ADMIN')) 34 | 35 | box.once("bootstrap", function() 36 | box.schema.user.create('tester', { password = 'pass'}) 37 | box.schema.user.grant('tester', 'read,write,execute', 'universe') 38 | end) 39 | 40 | i = 1 41 | j = 1 42 | results = {} 43 | d_results = {} 44 | fails = 0 45 | pool = lib_pool.new() 46 | 47 | pool.on_init = function(self) 48 | results[i] = 'init complete' 49 | i = i + 1 50 | end 51 | 52 | pool.on_connected_one = function(self, srv) 53 | results[i] = 'server connected' 54 | i = i + 1 55 | end 56 | 57 | pool.on_connected = function(self) 58 | results[i] = 'all nodes connected' 59 | i = i + 1 60 | end 61 | 62 | pool.on_disconnect_one = function(self, srv) 63 | d_results[j] = 'server disconnected' 64 | j = j + 1 65 | end 66 | 67 | pool.on_disconnect_zone = function(self, name) 68 | d_results[j] = 'zone ' .. name ..' disconnected' 69 | j = j + 1 70 | end 71 | 72 | pool.on_connfail = function(self, srv) 73 | fails = fails + 1 74 | end 75 | 76 | -- init 77 | fiber.create(function() 78 | pool:init(cfg) 79 | end) 80 | 81 | -------------------------------------------------------------------------------- /test/callback/master1.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tarantool 2 | lib_pool = require('connpool') 3 | os = require('os') 4 | fiber = require('fiber') 5 | 6 | local cfg = { 7 | pool_name = 'mypool'; 8 | servers = { 9 | { 10 | uri = 'localhost:33130', login = 'tester', 11 | password = 'pass', zone = 'myzone1' 12 | }; 13 | { 14 | uri = 'localhost:33131', login = 'tester', 15 | password = 'pass', zone = 'myzone2' 16 | }; 17 | { 18 | uri = 'localhost:33132', login = 'tester', 19 | password = 'pass', zone = 'myzone3' 20 | }; 21 | 22 | }; 23 | } 24 | 25 | box.cfg { 26 | slab_alloc_arena = 0.1; 27 | wal_mode = 'none'; 28 | listen = 33131; 29 | custom_proc_title = "master1" 30 | } 31 | 32 | require('console').listen(os.getenv('ADMIN')) 33 | 34 | box.once("bootstrap", function() 35 | box.schema.user.create('tester', { password = 'pass'}) 36 | box.schema.user.grant('tester', 'read,write,execute', 'universe') 37 | end) 38 | 39 | pool = lib_pool.new() 40 | 41 | -- init 42 | fiber.create(function() 43 | pool:init(cfg) 44 | end) 45 | -------------------------------------------------------------------------------- /test/callback/master2.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tarantool 2 | lib_pool = require('connpool') 3 | os = require('os') 4 | fiber = require('fiber') 5 | 6 | local cfg = { 7 | pool_name = 'mypool'; 8 | servers = { 9 | { 10 | uri = 'localhost:33130', login = 'tester', 11 | password = 'pass', zone = 'myzone1' 12 | }; 13 | { 14 | uri = 'localhost:33131', login = 'tester', 15 | password = 'pass', zone = 'myzone2' 16 | }; 17 | { 18 | uri = 'localhost:33132', login = 'tester', 19 | password = 'pass', zone = 'myzone3' 20 | }; 21 | }; 22 | } 23 | 24 | box.cfg { 25 | slab_alloc_arena = 0.1; 26 | wal_mode = 'none'; 27 | listen = 33132; 28 | custom_proc_title = "master2" 29 | } 30 | 31 | require('console').listen(os.getenv('ADMIN')) 32 | 33 | box.once("bootstrap", function() 34 | box.schema.user.create('tester', { password = 'pass'}) 35 | box.schema.user.grant('tester', 'read,write,execute', 'universe') 36 | end) 37 | 38 | pool = lib_pool.new() 39 | 40 | -- init 41 | fiber.create(function() 42 | pool:init(cfg) 43 | end) 44 | -------------------------------------------------------------------------------- /test/callback/suite.ini: -------------------------------------------------------------------------------- 1 | [default] 2 | core = tarantool 3 | description = connection pool callbacks tests 4 | script = master.lua 5 | lua_libs = lua/connpool.lua 6 | -------------------------------------------------------------------------------- /test/test-run.py: -------------------------------------------------------------------------------- 1 | ../test-run/test-run.py --------------------------------------------------------------------------------