* server connection was released too early, there were unsent data.
* put logged in clients immidiately to pause if SUSPEND.
* pause_mode cleanup
* Fix rare case when socket woken up from send-wait could stay stalling.
* More fair queueing of server connections. Before, a new query could
get a server connections before older one.
+ * Delay server release until everything is guaranteed to be sent.
= Features =
* SHOW SOCKETS command to have detailed info about state state.
* Put PgSocket ptr to log, to help tracking one connection.
+ * Various code cleanups.
2007-03-13 - PgBouncer 1.0 - "Tuunitud bemm"
return admin_error(admin, "admin access needed");
log_info("RESUME command issued");
- cf_pause_mode = 0;
+ cf_pause_mode = P_NONE;
switch (tmp_mode) {
- case 2:
+ case P_SUSPEND:
resume_all();
- case 1:
+ case P_PAUSE:
return admin_ready(admin, "RESUME");
default:
return admin_error(admin, "Pooler is not paused/suspended");
return admin_error(admin, "already suspended/paused");
log_info("SUSPEND command issued");
- cf_pause_mode = 2;
+ cf_pause_mode = P_SUSPEND;
admin->wait_for_response = 1;
suspend_pooler();
return admin_error(admin, "already suspended/paused");
log_info("PAUSE command issued");
- cf_pause_mode = 1;
+ cf_pause_mode = P_PAUSE;
admin->wait_for_response = 1;
return true;
continue;
switch (cf_pause_mode) {
- case 1:
+ case P_PAUSE:
admin_ready(admin, "PAUSE");
break;
- case 2:
+ case P_SUSPEND:
admin_ready(admin, "SUSPEND");
break;
default:
}
if (statlist_empty(&admin_pool->active_client_list)
- && cf_pause_mode == 2)
+ && cf_pause_mode == P_SUSPEND)
{
log_info("Admin disappeared when suspended, doing RESUME");
- cf_pause_mode = 0;
+ cf_pause_mode = P_NONE;
resume_all();
}
}
SV_TESTED /* pool->tested_server_list */
};
+enum PauseMode {
+ P_NONE = 0,
+ P_PAUSE = 1,
+ P_SUSPEND = 2
+};
+
#define is_server_socket(sk) ((sk)->state >= SV_FREE)
default:
fatal("bad client state: %d", client->state);
}
+ break;
+ case SBUF_EV_FLUSH:
+ /* client is not interested in it */
+ break;
}
return res;
}
disconnect_server(server, false, "test query failed");
} else
/* make immidiately available */
- change_server_state(server, SV_IDLE);
+ release_server(server);
}
/*
if (!active) {
active += suspend_socket_list(&pool->active_server_list);
active += suspend_socket_list(&pool->idle_server_list);
- active += statlist_count(&pool->tested_server_list);
/* as all clients are done, no need for them */
+ close_server_list(&pool->tested_server_list, "close unsafe fds on suspend");
close_server_list(&pool->used_server_list, "close unsafe fds on suspend");
}
if (pool->admin)
continue;
switch (cf_pause_mode) {
- case 0:
+ case P_NONE:
per_loop_activate(pool);
break;
- case 1:
+ case P_PAUSE:
active += per_loop_pause(pool);
break;
- case 2:
+ case P_SUSPEND:
active += per_loop_suspend(pool);
break;
}
}
switch (cf_pause_mode) {
- case 2:
+ case P_SUSPEND:
active += statlist_count(&login_client_list);
- case 1:
+ case P_PAUSE:
if (!active)
admin_pause_done();
default:
disconnect_server(server, true, "server idle timeout");
else if (cf_server_lifetime > 0 && age > cf_server_lifetime)
disconnect_server(server, true, "server lifetime over");
- else if (cf_pause_mode == 1)
+ else if (cf_pause_mode == P_PAUSE)
disconnect_server(server, true, "pause mode");
else if (idle_test && *cf_server_check_query) {
if (idle > cf_server_check_delay)
int cf_verbose = 0;
int cf_daemon = 0;
-int cf_pause_mode = 0;
+int cf_pause_mode = P_NONE;
int cf_shutdown = 0;
int cf_reboot = 0;
static char *cf_config_file;
static void handle_sigint(int sock, short flags, void *arg)
{
log_info("Got SIGINT, shutting down");
- cf_pause_mode = 1;
+ cf_pause_mode = P_PAUSE;
cf_shutdown = 1;
}
{
if (cf_pause_mode == 0) {
log_info("Got SIGUSR1, pausing all activity");
- cf_pause_mode = 1;
+ cf_pause_mode = P_PAUSE;
} else {
log_info("Got SIGUSR1, but already paused/suspended");
}
static void handle_sigusr2(int sock, short flags, void *arg)
{
switch (cf_pause_mode) {
- case 2:
+ case P_SUSPEND:
log_info("Got SIGUSR2, continuing from SUSPEND");
resume_all();
cf_pause_mode = 0;
break;
- case 1:
+ case P_PAUSE:
log_info("Got SIGUSR2, continuing from PAUSE");
cf_pause_mode = 0;
break;
- case 0:
+ case P_NONE:
log_info("Got SIGUSR1, but not paused/suspended");
}
}
return true;
/* try to get idle server, if allowed */
- if (cf_pause_mode == 1)
+ if (cf_pause_mode == P_PAUSE)
server = NULL;
else
server = first_socket(&pool->idle_server_list);
log_debug("finish_client_login: no welcome msg, pause");
client->wait_for_welcome = 1;
pause_client(client);
- if (!cf_pause_mode)
+ if (cf_pause_mode == P_NONE)
launch_new_connection(client->pool);
return false;
}
client->wait_for_welcome = 0;
slog_debug(client, "logged in");
+
+ /* in suspend, dont let send query */
+ if (cf_pause_mode == P_SUSPEND)
+ pause_client(client);
+
return true;
}
/* if the buffer is full, there can be more data available */
if (ok && sbuf->recv_pos == cf_sbuf_len)
goto try_more;
+
+ /* clean buffer */
+ sbuf_try_resync(sbuf);
+
+ /* notify proto that all is sent */
+ if (sbuf->send_pos == sbuf->recv_pos && sbuf->pkt_remain == 0)
+ sbuf_call_proto(sbuf, SBUF_EV_FLUSH);
}
/* check if there is any error pending on socket */
SBUF_EV_RECV_FAILED,
SBUF_EV_SEND_FAILED,
SBUF_EV_CONNECT_FAILED,
- SBUF_EV_CONNECT_OK
+ SBUF_EV_CONNECT_OK,
+ SBUF_EV_FLUSH
} SBufEvent;
typedef struct SBuf SBuf;
slog_debug(client, "query time: %d us", (int)total);
}
- if (ready && ( cf_pool_mode != POOL_SESSION
- || server->state == SV_TESTED))
- release_server(server);
-
return true;
}
Assert(server->state == SV_LOGIN);
server->request_time = get_cached_time();
res = handle_connect(server);
+ break;
+ case SBUF_EV_FLUSH:
+ if (server->ready
+ && (cf_pool_mode != POOL_SESSION
+ || server->state == SV_TESTED))
+ {
+ switch (server->state) {
+ case SV_ACTIVE:
+ case SV_TESTED:
+ release_server(server);
+ break;
+ default:
+ slog_warning(server, "EV_FLUSH with state=%d", server->state);
+ case SV_IDLE:
+ break;
+ }
+ }
+ res = true; /* unused actually */
+ break;
}
return res;
}