2017-05-26 12:17:45 +00:00
|
|
|
|
|
|
|
/*
|
2018-03-12 14:03:15 +00:00
|
|
|
* Odyssey.
|
2017-05-26 12:17:45 +00:00
|
|
|
*
|
2018-04-04 13:19:58 +00:00
|
|
|
* Scalable PostgreSQL connection pooler.
|
2017-05-26 12:17:45 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2018-08-28 14:43:46 +00:00
|
|
|
#include <ctype.h>
|
2017-05-31 15:47:15 +00:00
|
|
|
#include <inttypes.h>
|
2018-08-28 14:43:46 +00:00
|
|
|
#include <assert.h>
|
2017-05-26 12:17:45 +00:00
|
|
|
|
|
|
|
#include <machinarium.h>
|
2018-08-28 14:43:46 +00:00
|
|
|
#include <kiwi.h>
|
|
|
|
#include <odyssey.h>
|
2017-05-26 12:17:45 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
void
|
|
|
|
od_router_init(od_router_t *router)
|
2017-05-27 13:14:39 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
pthread_mutex_init(&router->lock, NULL);
|
|
|
|
od_rules_init(&router->rules);
|
|
|
|
od_route_pool_init(&router->route_pool);
|
|
|
|
router->clients = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
od_router_free(od_router_t *router)
|
2017-05-26 13:44:42 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_pool_free(&router->route_pool);
|
|
|
|
od_rules_free(&router->rules);
|
|
|
|
pthread_mutex_destroy(&router->lock);
|
|
|
|
}
|
2017-05-26 13:44:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
inline int
|
|
|
|
od_router_foreach(od_router_t *router,
|
|
|
|
od_route_pool_cb_t callback,
|
|
|
|
void **argv)
|
|
|
|
{
|
|
|
|
od_router_lock(router);
|
|
|
|
int rc;
|
|
|
|
rc = od_route_pool_foreach(&router->route_pool, callback, argv);
|
|
|
|
od_router_unlock(router);
|
|
|
|
return rc;
|
|
|
|
}
|
2017-05-26 13:44:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
static inline int
|
|
|
|
od_router_kill_clients_cb(od_route_t *route, void **argv)
|
|
|
|
{
|
|
|
|
(void)argv;
|
|
|
|
if (! route->rule->obsolete)
|
|
|
|
return 0;
|
|
|
|
od_route_lock(route);
|
|
|
|
od_route_kill_client_pool(route);
|
|
|
|
od_route_unlock(route);
|
|
|
|
return 0;
|
|
|
|
}
|
2017-07-03 14:32:48 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
int
|
|
|
|
od_router_reconfigure(od_router_t *router, od_rules_t *rules)
|
|
|
|
{
|
|
|
|
od_router_lock(router);
|
2017-05-26 13:44:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
int updates;
|
|
|
|
updates = od_rules_merge(&router->rules, rules);
|
2017-05-26 13:44:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
if (updates > 0) {
|
|
|
|
od_route_pool_foreach(&router->route_pool, od_router_kill_clients_cb,
|
|
|
|
NULL);
|
2017-05-26 13:44:42 +00:00
|
|
|
}
|
2018-12-06 14:23:15 +00:00
|
|
|
|
|
|
|
od_router_unlock(router);
|
|
|
|
return updates;
|
2017-05-26 13:44:42 +00:00
|
|
|
}
|
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
static inline int
|
|
|
|
od_router_expire_server_cb(od_server_t *server, void **argv)
|
2017-05-29 12:39:18 +00:00
|
|
|
{
|
2018-12-07 12:12:06 +00:00
|
|
|
od_route_t *route = server->route;
|
2018-12-06 14:23:15 +00:00
|
|
|
od_list_t *expire_list = argv[0];
|
|
|
|
int *count = argv[1];
|
2018-12-07 12:12:06 +00:00
|
|
|
|
|
|
|
/* remove server for server pool */
|
|
|
|
od_server_pool_set(&route->server_pool, server, OD_SERVER_UNDEF);
|
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_list_append(expire_list, &server->link);
|
|
|
|
(*count)++;
|
2018-12-07 12:12:06 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2017-05-29 14:53:21 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
static inline int
|
|
|
|
od_router_expire_server_tick_cb(od_server_t *server, void **argv)
|
|
|
|
{
|
|
|
|
od_route_t *route = server->route;
|
|
|
|
od_list_t *expire_list = argv[0];
|
|
|
|
int *count = argv[1];
|
|
|
|
|
|
|
|
/* advance idle time for 1 sec */
|
|
|
|
if (server->idle_time < route->rule->pool_ttl) {
|
|
|
|
server->idle_time++;
|
|
|
|
return 0;
|
|
|
|
}
|
2017-05-29 14:53:21 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* remove server for server pool */
|
|
|
|
od_server_pool_set(&route->server_pool, server, OD_SERVER_UNDEF);
|
2017-05-29 12:39:18 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* add to expire list */
|
|
|
|
od_list_append(expire_list, &server->link);
|
|
|
|
(*count)++;
|
2017-06-07 14:59:13 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2017-06-07 14:59:13 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
static inline int
|
|
|
|
od_router_expire_cb(od_route_t *route, void **argv)
|
|
|
|
{
|
|
|
|
od_route_lock(route);
|
2017-05-29 14:53:21 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* expire by config obsoletion */
|
|
|
|
if (route->rule->obsolete && !od_client_pool_total(&route->client_pool))
|
2017-06-07 14:59:13 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
od_server_pool_foreach(&route->server_pool,
|
|
|
|
OD_SERVER_IDLE,
|
|
|
|
od_router_expire_server_cb,
|
|
|
|
argv);
|
2017-06-07 14:59:13 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_unlock(route);
|
|
|
|
return 0;
|
2017-06-07 14:59:13 +00:00
|
|
|
}
|
2017-05-31 15:47:15 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
if (! route->rule->pool_ttl) {
|
|
|
|
od_route_unlock(route);
|
|
|
|
return 0;
|
2017-05-29 14:53:21 +00:00
|
|
|
}
|
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_server_pool_foreach(&route->server_pool,
|
|
|
|
OD_SERVER_IDLE,
|
|
|
|
od_router_expire_server_tick_cb,
|
|
|
|
argv);
|
|
|
|
|
|
|
|
od_route_unlock(route);
|
|
|
|
return 0;
|
2017-05-29 12:39:18 +00:00
|
|
|
}
|
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
int
|
|
|
|
od_router_expire(od_router_t *router, od_list_t *expire_list)
|
2017-06-07 14:59:13 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
int count = 0;
|
|
|
|
void *argv[] = { expire_list, &count };
|
|
|
|
od_router_foreach(router, od_router_expire_cb, argv);
|
|
|
|
return count;
|
2017-06-07 14:59:13 +00:00
|
|
|
}
|
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
static inline int
|
|
|
|
od_router_gc_cb(od_route_t *route, void **argv)
|
2017-05-26 12:17:45 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_pool_t *pool = argv[0];
|
|
|
|
od_route_lock(route);
|
2017-05-26 12:17:45 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
if (od_server_pool_total(&route->server_pool) > 0 ||
|
|
|
|
od_client_pool_total(&route->client_pool) > 0)
|
|
|
|
goto done;
|
2017-05-26 13:44:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
if (!od_route_is_dynamic(route) && !route->rule->obsolete)
|
|
|
|
goto done;
|
2017-05-27 13:14:39 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* remove route from route pool */
|
|
|
|
assert(pool->count > 0);
|
|
|
|
pool->count--;
|
|
|
|
od_list_unlink(&route->link);
|
2017-06-01 09:28:23 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_unlock(route);
|
2017-06-01 09:28:23 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* unref route rule and free route object */
|
|
|
|
od_rules_unref(route->rule);
|
|
|
|
od_route_free(route);
|
|
|
|
return 0;
|
|
|
|
done:
|
|
|
|
od_route_unlock(route);
|
|
|
|
return 0;
|
|
|
|
}
|
2017-06-07 13:01:47 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
void
|
|
|
|
od_router_gc(od_router_t *router)
|
|
|
|
{
|
|
|
|
void *argv[] = { &router->route_pool };
|
|
|
|
od_router_foreach(router, od_router_gc_cb, argv);
|
|
|
|
}
|
2017-06-01 09:28:23 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
void
|
|
|
|
od_router_stat(od_router_t *router,
|
|
|
|
uint64_t prev_time_us,
|
|
|
|
int prev_update,
|
|
|
|
od_route_pool_stat_cb_t callback,
|
|
|
|
void **argv)
|
|
|
|
{
|
|
|
|
od_router_lock(router);
|
|
|
|
od_route_pool_stat(&router->route_pool, prev_time_us, prev_update,
|
|
|
|
callback, argv);
|
|
|
|
od_router_unlock(router);
|
|
|
|
}
|
2017-05-27 13:14:39 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_router_status_t
|
|
|
|
od_router_route(od_router_t *router, od_config_t *config, od_client_t *client)
|
|
|
|
{
|
|
|
|
kiwi_be_startup_t *startup = &client->startup;
|
2017-05-30 15:04:59 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* match route */
|
2018-12-12 13:07:25 +00:00
|
|
|
assert(startup->database.value_len);
|
|
|
|
assert(startup->user.value_len);
|
2017-06-09 12:30:53 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_router_lock(router);
|
2017-05-31 10:49:12 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* match latest version of route rule */
|
|
|
|
od_rule_t *rule;
|
2018-12-12 13:07:25 +00:00
|
|
|
rule = od_rules_forward(&router->rules, startup->database.value,
|
|
|
|
startup->user.value);
|
2018-12-06 14:23:15 +00:00
|
|
|
if (rule == NULL) {
|
|
|
|
od_router_unlock(router);
|
|
|
|
return OD_ROUTER_ERROR_NOT_FOUND;
|
|
|
|
}
|
2017-05-31 10:49:12 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* force settings required by route */
|
|
|
|
od_route_id_t id = {
|
2018-12-12 13:07:25 +00:00
|
|
|
.database = startup->database.value,
|
|
|
|
.user = startup->user.value,
|
|
|
|
.database_len = startup->database.value_len,
|
2019-04-11 09:15:02 +00:00
|
|
|
.user_len = startup->user.value_len,
|
|
|
|
.physical_rep = false
|
2018-12-06 14:23:15 +00:00
|
|
|
};
|
|
|
|
if (rule->storage_db) {
|
|
|
|
id.database = rule->storage_db;
|
|
|
|
id.database_len = strlen(rule->storage_db) + 1;
|
|
|
|
}
|
|
|
|
if (rule->storage_user) {
|
|
|
|
id.user = rule->storage_user;
|
|
|
|
id.user_len = strlen(rule->storage_user) + 1;
|
|
|
|
}
|
2019-04-13 10:26:47 +00:00
|
|
|
if (rule->storage->storage_type == OD_RULE_STORAGE_REPLICATION_LOGICAL &&
|
|
|
|
startup->replication.value_len != 0) {
|
|
|
|
switch (startup->replication.value[0]) {
|
|
|
|
case 'o': /* on */
|
|
|
|
case 't': /* true */
|
|
|
|
case 'y': /* yes */
|
|
|
|
case '1': /* 1 */
|
2019-04-11 09:15:02 +00:00
|
|
|
id.physical_rep = true;
|
2019-04-13 10:26:47 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2019-04-11 09:15:02 +00:00
|
|
|
}
|
2018-12-06 14:23:15 +00:00
|
|
|
|
|
|
|
/* ensure global client_max limit */
|
|
|
|
if (config->client_max_set && router->clients >= config->client_max) {
|
|
|
|
od_router_unlock(router);
|
|
|
|
return OD_ROUTER_ERROR_LIMIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* match or create dynamic route */
|
|
|
|
od_route_t *route;
|
|
|
|
route = od_route_pool_match(&router->route_pool, &id, rule);
|
|
|
|
if (route == NULL) {
|
2018-12-07 12:12:06 +00:00
|
|
|
int is_shared;
|
|
|
|
is_shared = od_config_is_multi_workers(config);
|
|
|
|
route = od_route_pool_new(&router->route_pool, is_shared, &id, rule);
|
2018-12-06 14:23:15 +00:00
|
|
|
if (route == NULL) {
|
|
|
|
od_router_unlock(router);
|
|
|
|
return OD_ROUTER_ERROR;
|
2017-05-30 15:04:59 +00:00
|
|
|
}
|
2018-12-06 14:23:15 +00:00
|
|
|
}
|
|
|
|
router->clients++;
|
|
|
|
od_rules_ref(rule);
|
|
|
|
|
|
|
|
od_route_lock(route);
|
|
|
|
od_router_unlock(router);
|
|
|
|
|
|
|
|
/* ensure route client_max limit */
|
|
|
|
if (rule->client_max_set &&
|
|
|
|
od_client_pool_total(&route->client_pool) >= rule->client_max) {
|
|
|
|
od_route_unlock(route);
|
|
|
|
od_router_lock(router);
|
|
|
|
router->clients--;
|
|
|
|
od_rules_unref(rule);
|
|
|
|
od_router_unlock(router);
|
|
|
|
return OD_ROUTER_ERROR_LIMIT_ROUTE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add client to route client pool */
|
|
|
|
od_client_pool_set(&route->client_pool, client, OD_CLIENT_PENDING);
|
|
|
|
client->rule = rule;
|
|
|
|
client->route = route;
|
2017-05-30 15:04:59 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_unlock(route);
|
|
|
|
return OD_ROUTER_OK;
|
|
|
|
}
|
2017-05-27 13:14:39 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
void
|
|
|
|
od_router_unroute(od_router_t *router, od_client_t *client)
|
|
|
|
{
|
|
|
|
/* detach client from route */
|
|
|
|
assert(client->route);
|
|
|
|
assert(client->server == NULL);
|
|
|
|
|
|
|
|
od_router_lock(router);
|
|
|
|
assert(router->clients > 0);
|
|
|
|
router->clients--;
|
|
|
|
od_router_unlock(router);
|
|
|
|
|
|
|
|
od_route_t *route = client->route;
|
|
|
|
od_route_lock(route);
|
|
|
|
od_client_pool_set(&route->client_pool, client, OD_CLIENT_UNDEF);
|
|
|
|
client->route = NULL;
|
|
|
|
od_route_unlock(route);
|
|
|
|
}
|
2017-06-07 14:59:13 +00:00
|
|
|
|
2019-06-27 12:24:44 +00:00
|
|
|
od_router_status_t
|
|
|
|
od_router_wait_retry(od_router_t *router, od_client_t *client)
|
|
|
|
{
|
2019-07-06 14:40:48 +00:00
|
|
|
(void)router;
|
2019-06-27 12:24:44 +00:00
|
|
|
od_route_t *route = client->route;
|
|
|
|
od_server_t *server = client->server;
|
|
|
|
|
|
|
|
od_backend_close_connection(server);
|
|
|
|
|
|
|
|
od_route_lock(route);
|
|
|
|
uint32_t timeout = route->rule->pool_timeout;
|
|
|
|
/* we should prepare reconnection and continue */
|
|
|
|
|
|
|
|
od_server_pool_set(&route->server_pool, server, OD_SERVER_UNDEF);
|
|
|
|
client->server = NULL;
|
|
|
|
server->client = NULL;
|
|
|
|
server->route = NULL;
|
|
|
|
|
|
|
|
/* enqueue client (pending -> queue) */
|
|
|
|
od_client_pool_set(&route->client_pool, client, OD_CLIENT_QUEUE);
|
|
|
|
od_route_unlock(route);
|
|
|
|
|
|
|
|
assert(server->io.io == NULL);
|
|
|
|
od_server_free(server);
|
|
|
|
|
|
|
|
/* Wait until someone will pu connection back to pool */
|
|
|
|
return od_route_wait(route, timeout);
|
|
|
|
}
|
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_router_status_t
|
2019-01-30 09:30:31 +00:00
|
|
|
od_router_attach(od_router_t *router, od_config_t *config, od_client_t *client)
|
2018-12-06 14:23:15 +00:00
|
|
|
{
|
|
|
|
(void)router;
|
|
|
|
od_route_t *route = client->route;
|
|
|
|
assert(route != NULL);
|
2017-09-18 14:04:53 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_lock(route);
|
2017-05-29 12:39:18 +00:00
|
|
|
|
2018-12-07 12:12:06 +00:00
|
|
|
/* enqueue client (pending -> queue) */
|
|
|
|
od_client_pool_set(&route->client_pool, client, OD_CLIENT_QUEUE);
|
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* get client server from route server pool */
|
2019-06-13 08:55:01 +00:00
|
|
|
bool restart_read = false;
|
2018-12-06 14:23:15 +00:00
|
|
|
od_server_t *server;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
server = od_server_pool_next(&route->server_pool, OD_SERVER_IDLE);
|
|
|
|
if (server)
|
|
|
|
goto attach;
|
2017-05-31 10:49:12 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* always start new connection, if pool_size is zero */
|
|
|
|
if (route->rule->pool_size == 0)
|
2017-05-31 10:49:12 +00:00
|
|
|
break;
|
|
|
|
|
2018-12-07 12:12:06 +00:00
|
|
|
/* maybe start new connection */
|
|
|
|
if (od_server_pool_total(&route->server_pool) < route->rule->pool_size)
|
|
|
|
break;
|
|
|
|
|
2019-05-25 14:26:29 +00:00
|
|
|
/*
|
|
|
|
* unsubscribe from pending client read events during the time we wait
|
|
|
|
* for an available server
|
|
|
|
*/
|
2019-06-13 08:55:01 +00:00
|
|
|
restart_read = od_io_read_active(&client->io);
|
2019-05-25 14:26:29 +00:00
|
|
|
od_io_read_stop(&client->io);
|
|
|
|
|
2018-12-07 12:12:06 +00:00
|
|
|
od_route_unlock(route);
|
|
|
|
|
|
|
|
/* pool_size limit implementation.
|
|
|
|
*
|
|
|
|
* If the limit reached, wait wakeup condition for
|
|
|
|
* pool_timeout milliseconds.
|
|
|
|
*
|
|
|
|
* The condition triggered when a server connection
|
|
|
|
* put into idle state by DETACH events.
|
|
|
|
*/
|
|
|
|
uint32_t timeout = route->rule->pool_timeout;
|
|
|
|
if (timeout == 0)
|
|
|
|
timeout = UINT32_MAX;
|
|
|
|
int rc;
|
|
|
|
rc = od_route_wait(route, timeout);
|
|
|
|
if (rc == -1)
|
|
|
|
return OD_ROUTER_ERROR_TIMEDOUT;
|
|
|
|
|
|
|
|
od_route_lock(route);
|
2018-12-06 14:23:15 +00:00
|
|
|
}
|
2017-12-08 13:30:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_unlock(route);
|
2017-12-08 13:30:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* create new server object */
|
|
|
|
server = od_server_allocate();
|
|
|
|
if (server == NULL)
|
|
|
|
return OD_ROUTER_ERROR;
|
2019-01-30 09:30:31 +00:00
|
|
|
od_id_generate(&server->id, "s");
|
2018-12-06 14:23:15 +00:00
|
|
|
server->global = client->global;
|
|
|
|
server->route = route;
|
2017-12-08 13:30:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_lock(route);
|
2018-12-07 12:12:06 +00:00
|
|
|
/* xxx: maybe retry check for free server again */
|
2017-12-08 13:30:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
attach:
|
|
|
|
od_server_pool_set(&route->server_pool, server, OD_SERVER_ACTIVE);
|
|
|
|
od_client_pool_set(&route->client_pool, client, OD_CLIENT_ACTIVE);
|
2017-12-08 13:30:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
client->server = server;
|
|
|
|
server->client = client;
|
|
|
|
server->idle_time = 0;
|
|
|
|
server->key_client = client->key;
|
2017-05-30 11:34:08 +00:00
|
|
|
|
2018-12-07 12:12:06 +00:00
|
|
|
od_route_unlock(route);
|
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* attach server io to clients machine context */
|
2019-01-23 15:43:52 +00:00
|
|
|
if (server->io.io && od_config_is_multi_workers(config))
|
|
|
|
od_io_attach(&server->io);
|
2018-12-06 14:23:15 +00:00
|
|
|
|
2019-05-25 14:26:29 +00:00
|
|
|
/* maybe restore read events subscription */
|
2019-06-13 08:55:01 +00:00
|
|
|
if (restart_read)
|
|
|
|
od_io_read_start(&client->io);
|
2019-05-25 14:26:29 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
return OD_ROUTER_OK;
|
2017-05-26 12:17:45 +00:00
|
|
|
}
|
|
|
|
|
2018-08-28 14:43:46 +00:00
|
|
|
void
|
2018-12-06 14:23:15 +00:00
|
|
|
od_router_detach(od_router_t *router, od_config_t *config, od_client_t *client)
|
2017-05-26 12:17:45 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
(void)router;
|
|
|
|
od_route_t *route = client->route;
|
|
|
|
assert(route != NULL);
|
2018-02-02 12:50:23 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
/* detach from current machine event loop */
|
|
|
|
od_server_t *server = client->server;
|
|
|
|
if (od_config_is_multi_workers(config))
|
2019-01-23 15:43:52 +00:00
|
|
|
od_io_detach(&server->io);
|
2018-02-02 13:09:26 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_lock(route);
|
2017-05-26 13:44:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
client->server = NULL;
|
|
|
|
server->client = NULL;
|
|
|
|
od_server_pool_set(&route->server_pool, server, OD_SERVER_IDLE);
|
|
|
|
od_client_pool_set(&route->client_pool, client, OD_CLIENT_PENDING);
|
|
|
|
|
2018-12-07 12:12:06 +00:00
|
|
|
/* notify waiters */
|
|
|
|
if (route->client_pool.count_queue > 0)
|
|
|
|
od_route_signal(route);
|
2017-05-27 13:14:39 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_unlock(route);
|
2017-05-31 10:49:12 +00:00
|
|
|
}
|
2017-05-26 13:44:42 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
void
|
|
|
|
od_router_close(od_router_t *router, od_client_t *client)
|
2017-06-01 09:28:23 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
(void)router;
|
|
|
|
od_route_t *route = client->route;
|
|
|
|
assert(route != NULL);
|
2017-06-01 09:28:23 +00:00
|
|
|
|
2018-02-13 13:33:40 +00:00
|
|
|
od_server_t *server = client->server;
|
2018-12-06 14:23:15 +00:00
|
|
|
od_backend_close_connection(server);
|
|
|
|
|
|
|
|
od_route_lock(route);
|
|
|
|
|
|
|
|
od_client_pool_set(&route->client_pool, client, OD_CLIENT_PENDING);
|
|
|
|
od_server_pool_set(&route->server_pool, server, OD_SERVER_UNDEF);
|
2018-12-13 11:18:20 +00:00
|
|
|
client->server = NULL;
|
|
|
|
server->client = NULL;
|
|
|
|
server->route = NULL;
|
2018-12-06 14:23:15 +00:00
|
|
|
|
|
|
|
od_route_unlock(route);
|
|
|
|
|
2019-01-23 15:43:52 +00:00
|
|
|
assert(server->io.io == NULL);
|
2018-12-06 14:23:15 +00:00
|
|
|
od_server_free(server);
|
2017-05-26 13:44:42 +00:00
|
|
|
}
|
2017-05-27 13:14:39 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
static inline int
|
|
|
|
od_router_cancel_cmp(od_server_t *server, void **argv)
|
2017-05-27 13:14:39 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
return kiwi_key_cmp(&server->key_client, argv[0]);
|
2017-05-30 15:04:59 +00:00
|
|
|
}
|
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
static inline int
|
|
|
|
od_router_cancel_cb(od_route_t *route, void **argv)
|
2017-05-30 15:04:59 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_lock(route);
|
|
|
|
|
|
|
|
od_server_t *server;
|
|
|
|
server = od_server_pool_foreach(&route->server_pool, OD_SERVER_ACTIVE,
|
|
|
|
od_router_cancel_cmp, argv);
|
|
|
|
if (server)
|
|
|
|
{
|
|
|
|
od_router_cancel_t *cancel = argv[1];
|
|
|
|
cancel->id = server->id;
|
|
|
|
cancel->key = server->key;
|
|
|
|
cancel->storage = od_rules_storage_copy(route->rule->storage);
|
|
|
|
od_route_unlock(route);
|
|
|
|
if (cancel->storage == NULL)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
od_route_unlock(route);
|
|
|
|
return 0;
|
2017-05-31 10:49:12 +00:00
|
|
|
}
|
2017-05-30 15:04:59 +00:00
|
|
|
|
2018-08-28 14:43:46 +00:00
|
|
|
od_router_status_t
|
2018-12-06 14:23:15 +00:00
|
|
|
od_router_cancel(od_router_t *router, kiwi_key_t *key, od_router_cancel_t *cancel)
|
2017-12-08 13:30:42 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
/* match server by client forged key */
|
|
|
|
void *argv[] = { key, cancel };
|
|
|
|
int rc;
|
|
|
|
rc = od_router_foreach(router, od_router_cancel_cb, argv);
|
|
|
|
if (rc <= 0)
|
|
|
|
return OD_ROUTER_ERROR_NOT_FOUND;
|
|
|
|
return OD_ROUTER_OK;
|
2017-12-08 13:30:42 +00:00
|
|
|
}
|
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
static inline int
|
|
|
|
od_router_kill_cb(od_route_t *route, void **argv)
|
2017-05-31 10:49:12 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
od_route_lock(route);
|
|
|
|
od_route_kill_client(route, argv[0]);
|
|
|
|
od_route_unlock(route);
|
|
|
|
return 0;
|
2017-05-27 13:14:39 +00:00
|
|
|
}
|
2017-05-30 11:34:08 +00:00
|
|
|
|
2018-12-06 14:23:15 +00:00
|
|
|
void
|
|
|
|
od_router_kill(od_router_t *router, od_id_t *id)
|
2017-05-30 11:34:08 +00:00
|
|
|
{
|
2018-12-06 14:23:15 +00:00
|
|
|
void *argv[] = { id };
|
|
|
|
od_router_foreach(router, od_router_kill_cb, argv);
|
2017-05-30 11:34:08 +00:00
|
|
|
}
|