Default: 0 (disabled)
+==== idle_transaction_timeout ====
+
+If client has been in "idle in transaction" state longer, it will be disconnected.
+[seconds]
+
+Default: 0 (disabled)
+
=== Low-level network settings ===
==== pkt_buf ====
SocketState state:8; /* this also specifies socket location */
bool ready:1; /* server: accepts new query */
+ bool idle_tx:1; /* server: idling in tx */
bool close_needed:1; /* server: this socket must be closed ASAP */
bool setting_vars:1; /* server: setting client vars */
bool exec_on_connect:1; /* server: executing connect_query */
extern usec_t cf_query_wait_timeout;
extern usec_t cf_client_idle_timeout;
extern usec_t cf_client_login_timeout;
+extern usec_t cf_idle_transaction_timeout;
extern int cf_server_round_robin;
extern int cf_disable_pqexec;
extern usec_t cf_dns_max_ttl;
client->pool->stats.client_bytes += pkt->len;
/* tag the server as dirty */
- client->link->ready = 0;
+ client->link->ready = false;
+ client->link->idle_tx = false;
/* forward the packet */
sbuf_prepare_send(sbuf, &client->link->sbuf, pkt->len);
check_unused_servers(pool, &pool->idle_server_list, 1);
/* where query got did not get answer in query_timeout */
- if (cf_query_timeout > 0) {
+ if (cf_query_timeout > 0 || cf_idle_transaction_timeout > 0) {
statlist_for_each_safe(item, &pool->active_server_list, tmp) {
server = container_of(item, PgSocket, head);
Assert(server->state == SV_ACTIVE);
if (server->ready)
continue;
age = now - server->link->request_time;
- if (age > cf_query_timeout)
+ if (cf_query_timeout > 0 && age > cf_query_timeout) {
disconnect_server(server, true, "query timeout");
+ } else if (cf_idle_transaction_timeout > 0 &&
+ server->idle_tx &&
+ age > cf_idle_transaction_timeout)
+ {
+ disconnect_server(server, true, "idle transaction timeout");
+ }
}
}
usec_t cf_query_wait_timeout;
usec_t cf_client_idle_timeout;
usec_t cf_client_login_timeout;
+usec_t cf_idle_transaction_timeout;
usec_t cf_suspend_timeout;
usec_t g_suspend_start;
CF_ABS("query_wait_timeout", CF_TIME_USEC, cf_query_wait_timeout, 0, "0"),
CF_ABS("client_idle_timeout", CF_TIME_USEC, cf_client_idle_timeout, 0, "0"),
CF_ABS("client_login_timeout", CF_TIME_USEC, cf_client_login_timeout, 0, "60"),
+CF_ABS("idle_transaction_timeout", CF_TIME_USEC, cf_idle_transaction_timeout, 0, "0"),
CF_ABS("server_lifetime", CF_TIME_USEC, cf_server_lifetime, 0, "3600"),
CF_ABS("server_idle_timeout", CF_TIME_USEC, cf_server_idle_timeout, 0, "600"),
CF_ABS("server_connect_timeout", CF_TIME_USEC, cf_server_connect_timeout, 0, "15"),
/* process packets on logged in connection */
static bool handle_server_work(PgSocket *server, PktHdr *pkt)
{
- bool ready = 0;
+ bool ready = false;
+ bool idle_tx = false;
char state;
SBuf *sbuf = &server->sbuf;
PgSocket *client = server->link;
return false;
/* set ready only if no tx */
- if (state == 'I')
- ready = 1;
- else if (cf_pool_mode == POOL_STMT) {
+ if (state == 'I') {
+ ready = true;
+ } else if (cf_pool_mode == POOL_STMT) {
disconnect_server(server, true, "Long transactions not allowed");
return false;
+ } else if (state == 'T' || state == 'E') {
+ idle_tx = true;
}
break;
case 'T': /* RowDescription */
break;
}
+ server->idle_tx = idle_tx;
server->ready = ready;
server->pool->stats.server_bytes += pkt->len;