|
|
400eba |
From da9f4a9942f7a41ce8d07c7a73f67a0799424266 Mon Sep 17 00:00:00 2001
|
|
|
400eba |
From: Mark Reynolds <mreynolds@redhat.com>
|
|
|
400eba |
Date: Fri, 15 Jan 2016 11:35:16 -0500
|
|
|
400eba |
Subject: [PATCH] Ticket 48412 - worker threads do not detect abnormally closed
|
|
|
400eba |
connections
|
|
|
400eba |
|
|
|
400eba |
Bug Description: If a connection is abnormally closed there can still be
|
|
|
400eba |
data in the connection buffer(bytes vs offset). This prevents
|
|
|
400eba |
the connection from being removed from the connection table.
|
|
|
400eba |
The worker thread then goes into a loop trying to read this data
|
|
|
400eba |
on an already closed connection. If there are enough abnormally
|
|
|
400eba |
closed conenction eventually all the worker threads are stuck,
|
|
|
400eba |
and new connections are not accepted.
|
|
|
400eba |
|
|
|
400eba |
Fix Description: When looking if there is more data in the buffer check if the
|
|
|
400eba |
connection was closed, and return 0 (no more data).
|
|
|
400eba |
|
|
|
400eba |
Also did a little code cleanup.
|
|
|
400eba |
|
|
|
400eba |
https://fedorahosted.org/389/ticket/48412
|
|
|
400eba |
|
|
|
400eba |
Reviewed by: rmeggins(Thanks!)
|
|
|
400eba |
|
|
|
400eba |
(cherry picked from commit 30c4852a3d9ca527b78c0f89df5909bc9a268392)
|
|
|
400eba |
(cherry picked from commit cd45d032421b0ecf76d8cbb9b1c3aeef7680d9a2)
|
|
|
400eba |
---
|
|
|
400eba |
ldap/servers/slapd/connection.c | 46 ++++++++++++++++++++++++++++-------------
|
|
|
400eba |
1 file changed, 32 insertions(+), 14 deletions(-)
|
|
|
400eba |
|
|
|
400eba |
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
|
|
|
400eba |
index a3d123e..3e435a7 100644
|
|
|
400eba |
--- a/ldap/servers/slapd/connection.c
|
|
|
400eba |
+++ b/ldap/servers/slapd/connection.c
|
|
|
400eba |
@@ -1102,9 +1102,16 @@ connection_read_ldap_data(Connection *conn, PRInt32 *err)
|
|
|
400eba |
}
|
|
|
400eba |
|
|
|
400eba |
static size_t
|
|
|
400eba |
-conn_buffered_data_avail_nolock(Connection *conn)
|
|
|
400eba |
+conn_buffered_data_avail_nolock(Connection *conn, int *conn_closed)
|
|
|
400eba |
{
|
|
|
400eba |
- return conn->c_private->c_buffer_bytes - conn->c_private->c_buffer_offset;
|
|
|
400eba |
+ if ( (conn->c_sd == SLAPD_INVALID_SOCKET) || (conn->c_flags & CONN_FLAG_CLOSING) ) {
|
|
|
400eba |
+ /* connection is closed - ignore the buffer */
|
|
|
400eba |
+ *conn_closed = 1;
|
|
|
400eba |
+ return 0;
|
|
|
400eba |
+ } else {
|
|
|
400eba |
+ *conn_closed = 0;
|
|
|
400eba |
+ return conn->c_private->c_buffer_bytes - conn->c_private->c_buffer_offset;
|
|
|
400eba |
+ }
|
|
|
400eba |
}
|
|
|
400eba |
|
|
|
400eba |
/* Upon returning from this function, we have either:
|
|
|
400eba |
@@ -1127,6 +1134,7 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
|
|
|
400eba |
PRErrorCode err = 0;
|
|
|
400eba |
PRInt32 syserr = 0;
|
|
|
400eba |
size_t buffer_data_avail;
|
|
|
400eba |
+ int conn_closed = 0;
|
|
|
400eba |
|
|
|
400eba |
PR_EnterMonitor(conn->c_mutex);
|
|
|
400eba |
/*
|
|
|
400eba |
@@ -1142,7 +1150,7 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
|
|
|
400eba |
|
|
|
400eba |
*tag = LBER_DEFAULT;
|
|
|
400eba |
/* First check to see if we have buffered data from "before" */
|
|
|
400eba |
- if ((buffer_data_avail = conn_buffered_data_avail_nolock(conn))) {
|
|
|
400eba |
+ if ((buffer_data_avail = conn_buffered_data_avail_nolock(conn, &conn_closed))) {
|
|
|
400eba |
/* If so, use that data first */
|
|
|
400eba |
if ( 0 != get_next_from_buffer( buffer
|
|
|
400eba |
+ conn->c_private->c_buffer_offset,
|
|
|
400eba |
@@ -1157,7 +1165,7 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
|
|
|
400eba |
while (*tag == LBER_DEFAULT) {
|
|
|
400eba |
int ioblocktimeout_waits = config_get_ioblocktimeout() / CONN_TURBO_TIMEOUT_INTERVAL;
|
|
|
400eba |
/* We should never get here with data remaining in the buffer */
|
|
|
400eba |
- PR_ASSERT( !new_operation || 0 == conn_buffered_data_avail_nolock(conn) );
|
|
|
400eba |
+ PR_ASSERT( !new_operation || !conn_buffered_data_avail_nolock(conn, &conn_closed));
|
|
|
400eba |
/* We make a non-blocking read call */
|
|
|
400eba |
if (CONNECTION_BUFFER_OFF != conn->c_private->use_buffer) {
|
|
|
400eba |
ret = connection_read_ldap_data(conn,&err;;
|
|
|
400eba |
@@ -1269,8 +1277,12 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
|
|
|
400eba |
}
|
|
|
400eba |
}
|
|
|
400eba |
/* If there is remaining buffered data, set the flag to tell the caller */
|
|
|
400eba |
- if (conn_buffered_data_avail_nolock(conn)) {
|
|
|
400eba |
+ if (conn_buffered_data_avail_nolock(conn, &conn_closed)) {
|
|
|
400eba |
*remaining_data = 1;
|
|
|
400eba |
+ } else if (conn_closed){
|
|
|
400eba |
+ /* connection closed */
|
|
|
400eba |
+ ret = CONN_DONE;
|
|
|
400eba |
+ goto done;
|
|
|
400eba |
}
|
|
|
400eba |
|
|
|
400eba |
if ( *tag != LDAP_TAG_MESSAGE ) {
|
|
|
400eba |
@@ -1521,7 +1533,7 @@ connection_threadmain()
|
|
|
400eba |
continue;
|
|
|
400eba |
case CONN_SHUTDOWN:
|
|
|
400eba |
LDAPDebug( LDAP_DEBUG_TRACE,
|
|
|
400eba |
- "op_thread received shutdown signal\n", 0, 0, 0 );
|
|
|
400eba |
+ "op_thread received shutdown signal\n", 0, 0, 0 );
|
|
|
400eba |
g_decr_active_threadcnt();
|
|
|
400eba |
return;
|
|
|
400eba |
case CONN_FOUND_WORK_TO_DO:
|
|
|
400eba |
@@ -1542,8 +1554,9 @@ connection_threadmain()
|
|
|
400eba |
Slapi_DN *anon_sdn = slapi_sdn_new_normdn_byref( anon_dn );
|
|
|
400eba |
reslimit_update_from_dn( pb->pb_conn, anon_sdn );
|
|
|
400eba |
slapi_sdn_free( &anon_sdn );
|
|
|
400eba |
- if (slapi_reslimit_get_integer_limit(pb->pb_conn, pb->pb_conn->c_idletimeout_handle,
|
|
|
400eba |
- &idletimeout)
|
|
|
400eba |
+ if (slapi_reslimit_get_integer_limit(pb->pb_conn,
|
|
|
400eba |
+ pb->pb_conn->c_idletimeout_handle,
|
|
|
400eba |
+ &idletimeout)
|
|
|
400eba |
== SLAPI_RESLIMIT_STATUS_SUCCESS)
|
|
|
400eba |
{
|
|
|
400eba |
pb->pb_conn->c_idletimeout = idletimeout;
|
|
|
400eba |
@@ -1581,7 +1594,7 @@ connection_threadmain()
|
|
|
400eba |
op = pb->pb_op;
|
|
|
400eba |
maxthreads = config_get_maxthreadsperconn();
|
|
|
400eba |
more_data = 0;
|
|
|
400eba |
- ret = connection_read_operation(conn,op,&tag,&more_data);
|
|
|
400eba |
+ ret = connection_read_operation(conn, op, &tag, &more_data);
|
|
|
400eba |
if ((ret == CONN_DONE) || (ret == CONN_TIMEDOUT)) {
|
|
|
400eba |
slapi_log_error(SLAPI_LOG_CONNS, "connection_threadmain",
|
|
|
400eba |
"conn %" NSPRIu64 " read not ready due to %d - thread_turbo_flag %d more_data %d "
|
|
|
400eba |
@@ -1614,7 +1627,8 @@ connection_threadmain()
|
|
|
400eba |
/* turn off turbo mode immediately if any pb waiting in global queue */
|
|
|
400eba |
if (thread_turbo_flag && !WORK_Q_EMPTY) {
|
|
|
400eba |
thread_turbo_flag = 0;
|
|
|
400eba |
- LDAPDebug2Args(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " leaving turbo mode - pb_q is not empty %d\n",conn->c_connid,work_q_size);
|
|
|
400eba |
+ LDAPDebug2Args(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " leaving turbo mode - pb_q is not empty %d\n",
|
|
|
400eba |
+ conn->c_connid,work_q_size);
|
|
|
400eba |
}
|
|
|
400eba |
#endif
|
|
|
400eba |
|
|
|
400eba |
@@ -1639,7 +1653,8 @@ connection_threadmain()
|
|
|
400eba |
* should call connection_make_readable after the op is removed
|
|
|
400eba |
* connection_make_readable(conn);
|
|
|
400eba |
*/
|
|
|
400eba |
- LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " leaving turbo mode due to %d\n",conn->c_connid,ret,0);
|
|
|
400eba |
+ LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " leaving turbo mode due to %d\n",
|
|
|
400eba |
+ conn->c_connid,ret,0);
|
|
|
400eba |
goto done;
|
|
|
400eba |
case CONN_SHUTDOWN:
|
|
|
400eba |
LDAPDebug( LDAP_DEBUG_TRACE,
|
|
|
400eba |
@@ -1695,7 +1710,8 @@ connection_threadmain()
|
|
|
400eba |
*/
|
|
|
400eba |
conn->c_idlesince = curtime;
|
|
|
400eba |
connection_activity(conn, maxthreads);
|
|
|
400eba |
- LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " queued because more_data\n",conn->c_connid,0,0);
|
|
|
400eba |
+ LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " queued because more_data\n",
|
|
|
400eba |
+ conn->c_connid,0,0);
|
|
|
400eba |
} else {
|
|
|
400eba |
/* keep count of how many times maxthreads has blocked an operation */
|
|
|
400eba |
conn->c_maxthreadsblocked++;
|
|
|
400eba |
@@ -1770,13 +1786,15 @@ done:
|
|
|
400eba |
memset(pb, 0, sizeof(*pb));
|
|
|
400eba |
} else {
|
|
|
400eba |
/* delete from connection operation queue & decr refcnt */
|
|
|
400eba |
+ int conn_closed = 0;
|
|
|
400eba |
PR_EnterMonitor(conn->c_mutex);
|
|
|
400eba |
connection_remove_operation_ext( pb, conn, op );
|
|
|
400eba |
|
|
|
400eba |
/* If we're in turbo mode, we keep our reference to the connection alive */
|
|
|
400eba |
/* can't use the more_data var because connection could have changed in another thread */
|
|
|
400eba |
- more_data = conn_buffered_data_avail_nolock(conn) ? 1 : 0;
|
|
|
400eba |
- LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " check more_data %d thread_turbo_flag %d\n",conn->c_connid,more_data,thread_turbo_flag);
|
|
|
400eba |
+ more_data = conn_buffered_data_avail_nolock(conn, &conn_closed) ? 1 : 0;
|
|
|
400eba |
+ LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " check more_data %d thread_turbo_flag %d\n",
|
|
|
400eba |
+ conn->c_connid,more_data,thread_turbo_flag);
|
|
|
400eba |
if (!more_data) {
|
|
|
400eba |
if (!thread_turbo_flag) {
|
|
|
400eba |
/*
|
|
|
400eba |
--
|
|
|
400eba |
2.4.3
|
|
|
400eba |
|