2016-11-10 12:39:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* odissey.
|
|
|
|
*
|
|
|
|
* PostgreSQL connection pooler and request router.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
2016-11-15 11:38:31 +00:00
|
|
|
#include <stdarg.h>
|
2016-11-10 12:39:25 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2016-11-25 12:38:52 +00:00
|
|
|
#include <machinarium.h>
|
2016-11-10 12:39:25 +00:00
|
|
|
#include <soprano.h>
|
|
|
|
|
|
|
|
#include "od_macro.h"
|
|
|
|
#include "od_list.h"
|
2016-11-28 13:03:09 +00:00
|
|
|
#include "od_pid.h"
|
2016-11-28 14:47:39 +00:00
|
|
|
#include "od_syslog.h"
|
2016-11-10 12:39:25 +00:00
|
|
|
#include "od_log.h"
|
|
|
|
#include "od_scheme.h"
|
|
|
|
#include "od_lex.h"
|
|
|
|
#include "od_config.h"
|
2017-02-21 10:53:02 +00:00
|
|
|
#include "od_stat.h"
|
2016-11-10 12:39:25 +00:00
|
|
|
#include "od_server.h"
|
|
|
|
#include "od_server_pool.h"
|
2017-02-06 13:48:11 +00:00
|
|
|
#include "od_client.h"
|
|
|
|
#include "od_client_list.h"
|
|
|
|
#include "od_client_pool.h"
|
2016-11-11 10:42:30 +00:00
|
|
|
#include "od_route_id.h"
|
2016-11-11 09:56:56 +00:00
|
|
|
#include "od_route.h"
|
|
|
|
#include "od_route_pool.h"
|
2016-11-10 12:39:25 +00:00
|
|
|
#include "od.h"
|
2016-11-14 10:18:27 +00:00
|
|
|
#include "od_io.h"
|
2016-11-10 12:39:25 +00:00
|
|
|
#include "od_pooler.h"
|
2016-11-16 14:17:20 +00:00
|
|
|
#include "od_cancel.h"
|
2017-01-27 11:12:12 +00:00
|
|
|
#include "od_auth.h"
|
2017-04-05 12:46:26 +00:00
|
|
|
#include "od_tls.h"
|
2016-11-10 12:39:25 +00:00
|
|
|
#include "od_be.h"
|
|
|
|
|
2016-11-29 13:13:42 +00:00
|
|
|
int od_beterminate(od_server_t *server)
|
2016-11-15 13:07:04 +00:00
|
|
|
{
|
|
|
|
int rc;
|
2016-11-29 12:41:11 +00:00
|
|
|
so_stream_t *stream = &server->stream;
|
2016-11-15 13:07:04 +00:00
|
|
|
so_stream_reset(stream);
|
|
|
|
rc = so_fewrite_terminate(stream);
|
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
|
|
|
rc = od_write(server->io, stream);
|
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
2016-11-29 13:52:29 +00:00
|
|
|
server->count_request++;
|
2016-11-15 13:07:04 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-29 13:13:42 +00:00
|
|
|
int od_beclose(od_server_t *server)
|
2016-11-10 13:04:23 +00:00
|
|
|
{
|
2016-11-29 13:19:12 +00:00
|
|
|
od_route_t *route = server->route;
|
2016-11-11 09:56:56 +00:00
|
|
|
od_serverpool_set(&route->server_pool, server, OD_SUNDEF);
|
2016-11-10 13:04:23 +00:00
|
|
|
if (server->io) {
|
2017-03-23 12:55:36 +00:00
|
|
|
machine_close(server->io);
|
2017-04-18 13:28:43 +00:00
|
|
|
machine_free_io(server->io);
|
2016-11-10 13:04:23 +00:00
|
|
|
server->io = NULL;
|
|
|
|
}
|
2017-03-31 14:32:22 +00:00
|
|
|
if (server->tls) {
|
|
|
|
machine_free_tls(server->tls);
|
|
|
|
server->tls = NULL;
|
|
|
|
}
|
2016-11-16 11:39:17 +00:00
|
|
|
server->is_transaction = 0;
|
|
|
|
server->idle_time = 0;
|
2016-11-16 12:24:55 +00:00
|
|
|
so_keyinit(&server->key);
|
2016-11-16 13:15:14 +00:00
|
|
|
so_keyinit(&server->key_client);
|
2016-11-10 13:04:23 +00:00
|
|
|
od_serverfree(server);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-10 13:27:47 +00:00
|
|
|
static int
|
2016-11-29 13:13:42 +00:00
|
|
|
od_bestartup(od_server_t *server)
|
2016-11-10 13:27:47 +00:00
|
|
|
{
|
2017-04-05 12:21:43 +00:00
|
|
|
od_pooler_t *pooler = server->pooler;
|
2016-11-29 13:19:12 +00:00
|
|
|
od_route_t *route = server->route;
|
2016-11-29 12:41:11 +00:00
|
|
|
so_stream_t *stream = &server->stream;
|
2016-11-10 13:27:47 +00:00
|
|
|
so_stream_reset(stream);
|
2016-11-29 12:41:11 +00:00
|
|
|
so_fearg_t argv[] = {
|
2016-11-11 10:42:30 +00:00
|
|
|
{ "user", 5 }, { route->id.user, route->id.user_len },
|
|
|
|
{ "database", 9 }, { route->id.database, route->id.database_len }
|
2016-11-10 13:27:47 +00:00
|
|
|
};
|
|
|
|
int rc;
|
|
|
|
rc = so_fewrite_startup_message(stream, 4, argv);
|
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
2016-11-14 10:24:37 +00:00
|
|
|
rc = od_write(server->io, stream);
|
2017-04-05 12:21:43 +00:00
|
|
|
if (rc == -1) {
|
|
|
|
od_error(&pooler->od->log, server->io, "S (startup): write error: %s",
|
|
|
|
machine_error(server->io));
|
2016-11-29 13:52:29 +00:00
|
|
|
return -1;
|
2017-04-05 12:21:43 +00:00
|
|
|
}
|
2016-11-29 13:52:29 +00:00
|
|
|
server->count_request++;
|
|
|
|
return 0;
|
2016-11-10 13:27:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-01-27 10:17:38 +00:00
|
|
|
od_besetup(od_server_t *server)
|
2016-11-10 13:27:47 +00:00
|
|
|
{
|
2016-11-29 13:21:18 +00:00
|
|
|
od_pooler_t *pooler = server->pooler;
|
2016-11-29 12:41:11 +00:00
|
|
|
so_stream_t *stream = &server->stream;
|
2016-11-11 09:17:53 +00:00
|
|
|
while (1) {
|
2017-04-21 10:09:21 +00:00
|
|
|
so_stream_reset(stream);
|
2016-11-11 09:17:53 +00:00
|
|
|
int rc;
|
2017-04-20 12:26:13 +00:00
|
|
|
rc = od_read(server->io, &server->stream, INT_MAX);
|
2017-04-05 12:21:43 +00:00
|
|
|
if (rc == -1) {
|
2017-04-21 10:09:21 +00:00
|
|
|
od_error(&pooler->od->log, server->io, "S (setup): read error: %s",
|
2017-04-05 12:21:43 +00:00
|
|
|
machine_error(server->io));
|
2016-11-11 09:17:53 +00:00
|
|
|
return -1;
|
2017-04-05 12:21:43 +00:00
|
|
|
}
|
2017-04-21 10:59:22 +00:00
|
|
|
uint8_t type = *server->stream.s;
|
2017-01-27 11:55:37 +00:00
|
|
|
od_debug(&pooler->od->log, server->io, "S (setup): %c", type);
|
2016-11-11 09:17:53 +00:00
|
|
|
switch (type) {
|
|
|
|
/* ReadyForQuery */
|
|
|
|
case 'Z':
|
2017-04-21 10:59:22 +00:00
|
|
|
od_beset_ready(server, stream->s, so_stream_used(stream));
|
2016-11-11 09:17:53 +00:00
|
|
|
return 0;
|
|
|
|
/* Authentication */
|
|
|
|
case 'R':
|
2017-01-27 11:12:12 +00:00
|
|
|
rc = od_authbe(server);
|
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
2016-11-11 09:17:53 +00:00
|
|
|
break;
|
|
|
|
/* BackendKeyData */
|
|
|
|
case 'K':
|
2016-11-16 12:03:37 +00:00
|
|
|
rc = so_feread_key(&server->key,
|
|
|
|
stream->s, so_stream_used(stream));
|
|
|
|
if (rc == -1) {
|
2016-12-20 09:49:21 +00:00
|
|
|
od_error(&pooler->od->log, server->io,
|
2017-01-27 11:55:37 +00:00
|
|
|
"S (setup): failed to parse BackendKeyData message");
|
2016-11-16 12:03:37 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2016-11-11 09:17:53 +00:00
|
|
|
break;
|
|
|
|
/* ParameterStatus */
|
|
|
|
case 'S':
|
|
|
|
break;
|
|
|
|
/* NoticeResponce */
|
|
|
|
case 'N':
|
2016-11-10 13:27:47 +00:00
|
|
|
break;
|
2016-11-11 09:17:53 +00:00
|
|
|
/* ErrorResponce */
|
|
|
|
case 'E':
|
|
|
|
return -1;
|
|
|
|
default:
|
2016-12-20 09:42:39 +00:00
|
|
|
od_debug(&pooler->od->log, server->io,
|
2017-01-27 11:55:37 +00:00
|
|
|
"S (setup): unknown packet: %c", type);
|
2016-11-11 09:17:53 +00:00
|
|
|
return -1;
|
2016-11-10 13:27:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-10 13:04:23 +00:00
|
|
|
static int
|
2016-11-29 13:21:18 +00:00
|
|
|
od_beconnect(od_pooler_t *pooler, od_server_t *server)
|
2016-11-10 12:42:20 +00:00
|
|
|
{
|
2016-11-29 13:19:12 +00:00
|
|
|
od_route_t *route = server->route;
|
2016-11-29 13:09:16 +00:00
|
|
|
od_schemeserver_t *server_scheme = route->scheme->server;
|
2016-11-10 13:27:47 +00:00
|
|
|
|
|
|
|
/* place server to connect pool */
|
2016-11-11 09:56:56 +00:00
|
|
|
od_serverpool_set(&route->server_pool, server, OD_SCONNECT);
|
2016-11-10 13:27:47 +00:00
|
|
|
|
2016-12-08 13:47:37 +00:00
|
|
|
/* resolve server address */
|
2017-03-31 15:03:41 +00:00
|
|
|
machine_io_t resolver_context;
|
|
|
|
resolver_context = machine_create_io(pooler->env);
|
2017-01-13 09:31:31 +00:00
|
|
|
if (resolver_context == NULL) {
|
|
|
|
od_error(&pooler->od->log, NULL, "failed to resolve %s:%d",
|
|
|
|
server_scheme->host,
|
|
|
|
server_scheme->port);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-12-08 13:47:37 +00:00
|
|
|
char port[16];
|
|
|
|
snprintf(port, sizeof(port), "%d", server_scheme->port);
|
|
|
|
struct addrinfo *ai = NULL;
|
2016-11-10 13:27:47 +00:00
|
|
|
int rc;
|
2017-03-23 12:55:36 +00:00
|
|
|
rc = machine_getaddrinfo(resolver_context,
|
|
|
|
server_scheme->host, port, NULL, &ai, 0);
|
|
|
|
machine_close(resolver_context);
|
2017-04-18 13:28:43 +00:00
|
|
|
machine_free_io(resolver_context);
|
2016-12-08 13:47:37 +00:00
|
|
|
if (rc < 0) {
|
2016-12-20 09:49:21 +00:00
|
|
|
od_error(&pooler->od->log, NULL, "failed to resolve %s:%d",
|
2016-12-08 13:47:37 +00:00
|
|
|
server_scheme->host,
|
|
|
|
server_scheme->port);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
assert(ai != NULL);
|
|
|
|
|
|
|
|
/* connect to server */
|
2017-04-20 12:26:13 +00:00
|
|
|
rc = machine_connect(server->io, ai->ai_addr, INT_MAX);
|
2016-12-08 13:47:37 +00:00
|
|
|
freeaddrinfo(ai);
|
2016-11-10 13:27:47 +00:00
|
|
|
if (rc < 0) {
|
2016-12-20 09:49:21 +00:00
|
|
|
od_error(&pooler->od->log, NULL, "failed to connect to %s:%d",
|
2016-11-15 11:36:31 +00:00
|
|
|
server_scheme->host,
|
|
|
|
server_scheme->port);
|
2016-11-10 13:27:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2017-04-18 13:28:43 +00:00
|
|
|
rc = machine_set_readahead(server->io, pooler->od->scheme.readahead);
|
|
|
|
if (rc == -1) {
|
|
|
|
od_error(&pooler->od->log, NULL, "failed to set readahead");
|
|
|
|
return -1;
|
|
|
|
}
|
2016-12-22 12:38:57 +00:00
|
|
|
|
2017-03-31 15:03:41 +00:00
|
|
|
/* do tls handshake */
|
2017-04-05 12:46:26 +00:00
|
|
|
if (server_scheme->tls_verify != OD_TDISABLE) {
|
2017-04-05 13:27:34 +00:00
|
|
|
rc = od_tlsbe_connect(pooler->env, server->io, server->tls,
|
|
|
|
&server->stream,
|
|
|
|
&pooler->od->log, "S",
|
|
|
|
server_scheme);
|
2017-04-05 12:46:26 +00:00
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
|
|
|
}
|
2017-03-31 15:03:41 +00:00
|
|
|
|
2016-12-22 12:38:57 +00:00
|
|
|
od_log(&pooler->od->log, server->io, "S: new connection");
|
|
|
|
|
2016-11-10 13:27:47 +00:00
|
|
|
/* startup */
|
|
|
|
rc = od_bestartup(server);
|
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
2017-01-27 10:17:38 +00:00
|
|
|
/* server configuration */
|
|
|
|
rc = od_besetup(server);
|
2016-11-10 13:27:47 +00:00
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* server is ready to use */
|
2016-11-11 09:56:56 +00:00
|
|
|
od_serverpool_set(&route->server_pool, server, OD_SIDLE);
|
2016-11-10 13:04:23 +00:00
|
|
|
return 0;
|
2016-11-10 12:42:20 +00:00
|
|
|
}
|
|
|
|
|
2016-12-12 12:53:46 +00:00
|
|
|
static od_server_t*
|
|
|
|
od_bepop_pool(od_pooler_t *pooler, od_route_t *route)
|
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
od_server_t *server =
|
2016-12-13 14:45:48 +00:00
|
|
|
od_serverpool_next(&route->server_pool, OD_SIDLE);
|
2016-12-12 12:53:46 +00:00
|
|
|
if (! server)
|
|
|
|
break;
|
|
|
|
/* ensure that connection is still viable */
|
2017-03-23 12:55:36 +00:00
|
|
|
if (! machine_connected(server->io)) {
|
2016-12-22 12:52:15 +00:00
|
|
|
od_log(&pooler->od->log, server->io,
|
|
|
|
"S (idle): closed connection");
|
2016-12-12 12:53:46 +00:00
|
|
|
od_beclose(server);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
return server;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-29 13:13:42 +00:00
|
|
|
od_server_t*
|
2017-02-20 14:39:36 +00:00
|
|
|
od_bepop(od_pooler_t *pooler, od_route_t *route, od_client_t *client)
|
2016-11-10 12:42:20 +00:00
|
|
|
{
|
2017-02-20 14:39:36 +00:00
|
|
|
od_server_t *server;
|
|
|
|
|
|
|
|
/* try to fetch server connection from idle pool */
|
|
|
|
int rc;
|
|
|
|
for (;;) {
|
|
|
|
if (route->server_pool.count_idle > 0) {
|
|
|
|
server = od_bepop_pool(pooler, route);
|
|
|
|
/* retry */
|
|
|
|
if (server == NULL)
|
|
|
|
continue;
|
|
|
|
goto ready;
|
|
|
|
}
|
|
|
|
assert(! route->server_pool.count_idle);
|
|
|
|
|
|
|
|
if (od_clientpool_total(&route->client_pool) <= route->scheme->pool_size)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
od_debug(&pooler->od->log, client->io,
|
|
|
|
"C (pop): pool limit reached (%d), waiting",
|
|
|
|
route->scheme->pool_size);
|
|
|
|
|
|
|
|
/* wait */
|
|
|
|
od_clientpool_set(&route->client_pool, client, OD_CQUEUE);
|
|
|
|
|
2017-03-23 12:55:36 +00:00
|
|
|
rc = machine_condition(pooler->env, route->scheme->pool_timeout);
|
2017-02-20 14:39:36 +00:00
|
|
|
if (rc < 0) {
|
|
|
|
od_debug(&pooler->od->log, client->io,
|
|
|
|
"C (pop): server wait timeout");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
od_clientpool_set(&route->client_pool, client, OD_CPENDING);
|
|
|
|
|
|
|
|
od_debug(&pooler->od->log, client->io,
|
|
|
|
"C (pop): resumed");
|
|
|
|
|
|
|
|
/* retry */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-11-10 13:04:23 +00:00
|
|
|
/* create new server connection */
|
|
|
|
server = od_serveralloc();
|
|
|
|
if (server == NULL)
|
|
|
|
return NULL;
|
2017-03-23 12:55:36 +00:00
|
|
|
server->io = machine_create_io(pooler->env);
|
2016-11-10 13:04:23 +00:00
|
|
|
if (server->io == NULL) {
|
|
|
|
od_serverfree(server);
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-03-31 14:32:22 +00:00
|
|
|
|
|
|
|
/* set network options */
|
2017-03-23 12:55:36 +00:00
|
|
|
machine_set_nodelay(server->io, pooler->od->scheme.nodelay);
|
2016-11-28 12:42:52 +00:00
|
|
|
if (pooler->od->scheme.keepalive > 0)
|
2017-03-23 12:55:36 +00:00
|
|
|
machine_set_keepalive(server->io, 1, pooler->od->scheme.keepalive);
|
2017-03-31 14:32:22 +00:00
|
|
|
|
|
|
|
/* set tls options */
|
|
|
|
od_schemeserver_t *server_scheme;
|
|
|
|
server_scheme = route->scheme->server;
|
|
|
|
if (server_scheme->tls_verify != OD_TDISABLE) {
|
2017-04-05 13:27:34 +00:00
|
|
|
server->tls = od_tlsbe(pooler->env, server_scheme);
|
2017-03-31 14:32:22 +00:00
|
|
|
if (server->tls == NULL) {
|
|
|
|
od_serverfree(server);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-11 09:17:53 +00:00
|
|
|
server->pooler = pooler;
|
2016-11-10 13:04:23 +00:00
|
|
|
server->route = route;
|
|
|
|
rc = od_beconnect(pooler, server);
|
|
|
|
if (rc == -1) {
|
2016-11-14 13:32:19 +00:00
|
|
|
od_beclose(server);
|
2016-11-10 13:04:23 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2017-02-20 14:39:36 +00:00
|
|
|
|
2016-11-10 13:27:47 +00:00
|
|
|
ready:
|
2017-02-20 14:39:36 +00:00
|
|
|
/* mark client as active */
|
|
|
|
od_clientpool_set(&route->client_pool, client,
|
|
|
|
OD_CACTIVE);
|
|
|
|
|
2016-11-10 13:27:47 +00:00
|
|
|
/* server is ready to use */
|
2016-11-11 09:56:56 +00:00
|
|
|
od_serverpool_set(&route->server_pool, server,
|
2016-11-10 13:27:47 +00:00
|
|
|
OD_SACTIVE);
|
2016-12-22 13:06:39 +00:00
|
|
|
server->idle_time = 0;
|
2016-11-10 12:42:20 +00:00
|
|
|
return server;
|
|
|
|
}
|
2016-11-14 13:43:42 +00:00
|
|
|
|
2017-04-21 10:59:22 +00:00
|
|
|
int od_beset_ready(od_server_t *server, uint8_t *data, int size)
|
2016-11-15 11:14:26 +00:00
|
|
|
{
|
|
|
|
int status;
|
2017-04-21 10:59:22 +00:00
|
|
|
int rc;
|
|
|
|
rc = so_feread_ready(&status, data, size);
|
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
2016-11-15 11:14:26 +00:00
|
|
|
if (status == 'I') {
|
|
|
|
/* no active transaction */
|
2016-11-16 11:16:35 +00:00
|
|
|
server->is_transaction = 0;
|
2016-11-15 11:14:26 +00:00
|
|
|
} else
|
|
|
|
if (status == 'T' || status == 'E') {
|
|
|
|
/* in active transaction or in interrupted
|
|
|
|
* transaction block */
|
2016-11-16 11:16:35 +00:00
|
|
|
server->is_transaction = 1;
|
2016-11-15 11:14:26 +00:00
|
|
|
}
|
2016-11-29 13:52:29 +00:00
|
|
|
server->count_reply++;
|
2016-11-15 11:14:26 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
2016-11-29 13:13:42 +00:00
|
|
|
od_beready_wait(od_server_t *server, char *procedure, int time_ms)
|
2016-11-15 11:14:26 +00:00
|
|
|
{
|
2016-11-29 13:21:18 +00:00
|
|
|
od_pooler_t *pooler = server->pooler;
|
2016-11-29 12:41:11 +00:00
|
|
|
so_stream_t *stream = &server->stream;
|
2017-03-10 12:06:18 +00:00
|
|
|
/* wait for response */
|
2016-11-15 11:14:26 +00:00
|
|
|
while (1) {
|
2017-04-21 10:09:21 +00:00
|
|
|
so_stream_reset(stream);
|
2016-11-15 11:14:26 +00:00
|
|
|
int rc;
|
2016-11-25 13:27:02 +00:00
|
|
|
rc = od_read(server->io, stream, time_ms);
|
2017-04-05 12:21:43 +00:00
|
|
|
if (rc == -1) {
|
2017-04-21 10:09:21 +00:00
|
|
|
od_error(&pooler->od->log, server->io, "S (%s): read error: %s",
|
2017-04-05 12:21:43 +00:00
|
|
|
procedure, machine_error(server->io));
|
2016-11-15 11:14:26 +00:00
|
|
|
return -1;
|
2017-04-05 12:21:43 +00:00
|
|
|
}
|
2017-04-21 10:59:22 +00:00
|
|
|
uint8_t type = stream->s[rc];
|
2016-12-20 09:42:39 +00:00
|
|
|
od_debug(&pooler->od->log, server->io, "S (%s): %c",
|
2016-12-14 14:02:32 +00:00
|
|
|
procedure, type);
|
2016-11-15 11:14:26 +00:00
|
|
|
/* ReadyForQuery */
|
2017-04-21 10:59:22 +00:00
|
|
|
if (type == 'Z') {
|
|
|
|
od_beset_ready(server, stream->s + rc,
|
|
|
|
so_stream_used(stream) - rc);
|
2016-11-15 11:14:26 +00:00
|
|
|
break;
|
2017-04-21 10:59:22 +00:00
|
|
|
}
|
2016-11-15 11:14:26 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-15 11:17:22 +00:00
|
|
|
static inline int
|
2016-11-29 13:13:42 +00:00
|
|
|
od_bequery(od_server_t *server, char *procedure, char *query, int len)
|
2016-11-15 11:17:22 +00:00
|
|
|
{
|
2017-04-05 12:21:43 +00:00
|
|
|
od_pooler_t *pooler = server->pooler;
|
2016-11-15 11:17:22 +00:00
|
|
|
int rc;
|
2016-11-29 12:41:11 +00:00
|
|
|
so_stream_t *stream = &server->stream;
|
2016-11-15 11:17:22 +00:00
|
|
|
so_stream_reset(stream);
|
|
|
|
rc = so_fewrite_query(stream, query, len);
|
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
|
|
|
rc = od_write(server->io, stream);
|
2017-04-05 12:21:43 +00:00
|
|
|
if (rc == -1) {
|
|
|
|
od_error(&pooler->od->log, server->io, "S (%s): write error: %s",
|
|
|
|
procedure, machine_error(server->io));
|
2016-11-15 11:17:22 +00:00
|
|
|
return -1;
|
2017-04-05 12:21:43 +00:00
|
|
|
}
|
2016-11-29 13:52:29 +00:00
|
|
|
server->count_request++;
|
2017-04-20 12:26:13 +00:00
|
|
|
rc = od_beready_wait(server, procedure, INT_MAX);
|
2016-11-16 14:17:20 +00:00
|
|
|
if (rc == -1)
|
2016-11-15 11:17:22 +00:00
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-20 14:39:36 +00:00
|
|
|
static inline int
|
|
|
|
od_bereset(od_server_t *server)
|
2016-11-14 13:43:42 +00:00
|
|
|
{
|
2016-11-29 13:21:18 +00:00
|
|
|
od_pooler_t *pooler = server->pooler;
|
2016-11-29 13:19:12 +00:00
|
|
|
od_route_t *route = server->route;
|
2016-11-14 14:16:31 +00:00
|
|
|
|
|
|
|
/* place server to reset pool */
|
|
|
|
od_serverpool_set(&route->server_pool, server,
|
|
|
|
OD_SRESET);
|
|
|
|
|
2017-02-17 09:06:55 +00:00
|
|
|
/* server left in copy mode */
|
|
|
|
if (server->is_copy) {
|
|
|
|
od_debug(&pooler->od->log, server->io,
|
|
|
|
"S (reset): copy is active, dropping");
|
|
|
|
goto drop;
|
|
|
|
}
|
|
|
|
|
2017-02-16 10:02:50 +00:00
|
|
|
/* support route rollback off */
|
2017-02-16 10:18:39 +00:00
|
|
|
if (! route->scheme->rollback) {
|
|
|
|
if (server->is_transaction) {
|
|
|
|
od_debug(&pooler->od->log, server->io,
|
|
|
|
"S (reset): in active transaction, dropping");
|
|
|
|
goto drop;
|
|
|
|
}
|
2017-02-16 10:02:50 +00:00
|
|
|
}
|
|
|
|
|
2017-02-16 10:15:23 +00:00
|
|
|
/* support route cancel off */
|
|
|
|
if (! route->scheme->cancel) {
|
|
|
|
if (! od_server_is_sync(server)) {
|
|
|
|
od_debug(&pooler->od->log, server->io,
|
|
|
|
"S (reset): not synchronized, dropping");
|
|
|
|
goto drop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-29 14:40:53 +00:00
|
|
|
/* Server is not synchronized.
|
|
|
|
*
|
|
|
|
* Number of queries sent to server is not equal
|
|
|
|
* to the number of received replies.
|
|
|
|
*
|
2017-02-16 10:18:39 +00:00
|
|
|
* Do the following logic, until server becomes
|
2016-11-29 14:40:53 +00:00
|
|
|
* synchronized:
|
|
|
|
*
|
|
|
|
* 1. Wait each ReadyForQuery until we receive all
|
|
|
|
* replies with 1 sec timeout.
|
|
|
|
*
|
|
|
|
* 2. Send Cancel in other connection.
|
|
|
|
*
|
2016-11-29 14:48:49 +00:00
|
|
|
* It is possible that client could previously
|
|
|
|
* pipeline server with requests. Each request
|
|
|
|
* may stall database on its own and may require
|
|
|
|
* additional Cancel request.
|
2016-11-25 15:04:12 +00:00
|
|
|
*
|
2017-02-16 10:18:39 +00:00
|
|
|
* 3. Continue with (1)
|
2016-11-25 15:04:12 +00:00
|
|
|
*/
|
2016-11-29 14:40:53 +00:00
|
|
|
int wait_timeout = 1000;
|
|
|
|
int wait_try = 0;
|
|
|
|
int wait_try_cancel = 0;
|
|
|
|
int wait_cancel_limit = 1;
|
|
|
|
int rc = 0;
|
|
|
|
for (;;) {
|
|
|
|
while (! od_server_is_sync(server)) {
|
2016-12-20 09:42:39 +00:00
|
|
|
od_debug(&pooler->od->log, server->io,
|
|
|
|
"S (reset): not synchronized, wait for %d msec (#%d)",
|
2016-11-29 14:40:53 +00:00
|
|
|
wait_timeout,
|
|
|
|
wait_try);
|
|
|
|
wait_try++;
|
|
|
|
rc = od_beready_wait(server, "reset", wait_timeout);
|
|
|
|
if (rc == -1)
|
|
|
|
break;
|
|
|
|
}
|
2016-11-25 13:27:02 +00:00
|
|
|
if (rc == -1) {
|
2017-03-23 12:55:36 +00:00
|
|
|
if (! machine_read_timedout(server->io))
|
2016-11-25 13:27:02 +00:00
|
|
|
goto error;
|
2016-11-29 14:40:53 +00:00
|
|
|
if (wait_try_cancel == wait_cancel_limit) {
|
2016-12-20 09:42:39 +00:00
|
|
|
od_debug(&pooler->od->log, server->io,
|
|
|
|
"S (reset): server cancel limit reached, dropping");
|
2016-11-29 14:40:53 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2016-12-20 09:42:39 +00:00
|
|
|
od_debug(&pooler->od->log, server->io,
|
|
|
|
"S (reset): not responded, cancel (#%d)",
|
2016-11-29 14:40:53 +00:00
|
|
|
wait_try_cancel);
|
|
|
|
wait_try_cancel++;
|
2016-11-25 15:04:12 +00:00
|
|
|
rc = od_cancel_of(pooler, route->scheme->server, &server->key);
|
|
|
|
if (rc < 0)
|
2016-11-29 14:48:49 +00:00
|
|
|
goto error;
|
2016-11-29 14:40:53 +00:00
|
|
|
continue;
|
2016-11-25 13:27:02 +00:00
|
|
|
}
|
2016-11-29 14:40:53 +00:00
|
|
|
assert(od_server_is_sync(server));
|
|
|
|
break;
|
2016-11-25 13:27:02 +00:00
|
|
|
}
|
2016-12-20 09:42:39 +00:00
|
|
|
od_debug(&pooler->od->log, server->io, "S (reset): synchronized");
|
2016-11-25 13:27:02 +00:00
|
|
|
|
2016-11-15 11:28:28 +00:00
|
|
|
/* send rollback in case if server has an active
|
|
|
|
* transaction running */
|
2017-02-16 10:18:39 +00:00
|
|
|
if (route->scheme->rollback) {
|
|
|
|
if (server->is_transaction) {
|
|
|
|
char query_rlb[] = "ROLLBACK";
|
|
|
|
rc = od_bequery(server, "reset rollback", query_rlb,
|
|
|
|
sizeof(query_rlb));
|
|
|
|
if (rc == -1)
|
|
|
|
goto error;
|
|
|
|
assert(! server->is_transaction);
|
|
|
|
}
|
2016-11-15 11:28:28 +00:00
|
|
|
}
|
|
|
|
|
2016-11-14 14:16:31 +00:00
|
|
|
/* send reset query */
|
2017-02-14 15:33:08 +00:00
|
|
|
if (route->scheme->discard) {
|
2017-02-14 15:29:56 +00:00
|
|
|
char query_reset[] = "DISCARD ALL";
|
|
|
|
rc = od_bequery(server, "reset", query_reset,
|
|
|
|
sizeof(query_reset));
|
|
|
|
if (rc == -1)
|
|
|
|
goto error;
|
|
|
|
}
|
2016-11-14 14:16:31 +00:00
|
|
|
|
|
|
|
/* server is ready to use */
|
|
|
|
od_serverpool_set(&route->server_pool, server,
|
|
|
|
OD_SIDLE);
|
2017-02-20 14:39:36 +00:00
|
|
|
return 1;
|
2016-11-14 14:16:31 +00:00
|
|
|
error:
|
2016-11-25 13:27:02 +00:00
|
|
|
od_beterminate(server);
|
2016-11-14 14:16:31 +00:00
|
|
|
od_beclose(server);
|
|
|
|
return -1;
|
2017-02-16 10:02:50 +00:00
|
|
|
drop:
|
|
|
|
od_beterminate(server);
|
|
|
|
od_beclose(server);
|
|
|
|
return 0;
|
2016-11-14 13:43:42 +00:00
|
|
|
}
|
2017-02-20 14:39:36 +00:00
|
|
|
|
|
|
|
int od_berelease(od_server_t *server)
|
|
|
|
{
|
|
|
|
od_pooler_t *pooler = server->pooler;
|
|
|
|
od_route_t *route = server->route;
|
|
|
|
|
|
|
|
/* cleanup server */
|
|
|
|
int rc;
|
|
|
|
rc = od_bereset(server);
|
|
|
|
if (rc <= 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
/* wake up first client waiting for server connection */
|
|
|
|
if (route->client_pool.count_queue > 0) {
|
|
|
|
od_client_t *waiter;
|
|
|
|
waiter = od_clientpool_next(&route->client_pool, OD_CQUEUE);
|
2017-03-23 12:55:36 +00:00
|
|
|
rc = machine_signal(pooler->env, waiter->id_fiber);
|
2017-02-20 14:39:36 +00:00
|
|
|
assert(rc == 0);
|
|
|
|
od_debug(&pooler->od->log, waiter->io,
|
|
|
|
"C (release): waking up");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2017-03-07 13:20:12 +00:00
|
|
|
|
|
|
|
int od_beconfigure(od_server_t *server, so_bestartup_t *startup)
|
|
|
|
{
|
|
|
|
od_pooler_t *pooler = server->pooler;
|
|
|
|
|
|
|
|
char query_configure[1024];
|
|
|
|
int size = 0;
|
|
|
|
so_parameter_t *param =
|
|
|
|
(so_parameter_t*)startup->params.buf.s;
|
|
|
|
so_parameter_t *end =
|
|
|
|
(so_parameter_t*)startup->params.buf.p;
|
|
|
|
for (; param < end; param = so_parameter_next(param)) {
|
|
|
|
if (param == startup->user ||
|
|
|
|
param == startup->database)
|
|
|
|
continue;
|
|
|
|
size += snprintf(query_configure + size,
|
|
|
|
sizeof(query_configure) - size,
|
|
|
|
"SET %s=%s;",
|
|
|
|
so_parameter_name(param),
|
|
|
|
so_parameter_value(param));
|
|
|
|
}
|
|
|
|
if (size == 0)
|
|
|
|
return 0;
|
|
|
|
od_debug(&pooler->od->log, server->io,
|
|
|
|
"S (configure): %s", query_configure);
|
|
|
|
int rc;
|
|
|
|
rc = od_bequery(server, "configure", query_configure,
|
|
|
|
size + 1);
|
|
|
|
return rc;
|
|
|
|
}
|