Blame SOURCES/0006-Ticket-51131-improve-mutex-alloc-in-conntable.patch

be9751
From 1085823bf5586d55103cfba249fdf212e9afcb7c Mon Sep 17 00:00:00 2001
be9751
From: William Brown <william@blackhats.net.au>
be9751
Date: Thu, 4 Jun 2020 11:51:53 +1000
be9751
Subject: [PATCH] Ticket 51131 - improve mutex alloc in conntable
be9751
be9751
Bug Description: We previously did delayed allocation
be9751
of mutexs, which @tbordaz noted can lead to high usage
be9751
of the pthread mutex init routines. This was done under
be9751
the conntable lock, as well as cleaning the connection
be9751
be9751
Fix Description: rather than delayed allocation, we
be9751
initialise everything at start up instead, which means
be9751
that while startup may have a delay, at run time we have
be9751
a smaller and lighter connection allocation routine,
be9751
that is able to release the CT lock sooner.
be9751
be9751
https://pagure.io/389-ds-base/issue/51131
be9751
be9751
Author: William Brown <william@blackhats.net.au>
be9751
be9751
Review by: ???
be9751
---
be9751
 ldap/servers/slapd/conntable.c | 86 +++++++++++++++++++---------------
be9751
 1 file changed, 47 insertions(+), 39 deletions(-)
be9751
be9751
diff --git a/ldap/servers/slapd/conntable.c b/ldap/servers/slapd/conntable.c
be9751
index b23dc3435..feb9c0d75 100644
be9751
--- a/ldap/servers/slapd/conntable.c
be9751
+++ b/ldap/servers/slapd/conntable.c
be9751
@@ -138,10 +138,21 @@ connection_table_new(int table_size)
be9751
     ct->conn_next_offset = 1;
be9751
     ct->conn_free_offset = 1;
be9751
 
be9751
+    pthread_mutexattr_t monitor_attr = {0};
be9751
+    pthread_mutexattr_init(&monitor_attr);
be9751
+    pthread_mutexattr_settype(&monitor_attr, PTHREAD_MUTEX_RECURSIVE);
be9751
+
be9751
     /* We rely on the fact that we called calloc, which zeros the block, so we don't
be9751
      * init any structure element unless a zero value is troublesome later
be9751
      */
be9751
     for (i = 0; i < table_size; i++) {
be9751
+        /*
be9751
+         * Technically this is a no-op due to calloc, but we should always be
be9751
+         * careful with things like this ....
be9751
+         */
be9751
+        ct->c[i].c_state = CONN_STATE_FREE;
be9751
+        /* Start the conn setup. */
be9751
+
be9751
         LBER_SOCKET invalid_socket;
be9751
         /* DBDB---move this out of here once everything works */
be9751
         ct->c[i].c_sb = ber_sockbuf_alloc();
be9751
@@ -161,11 +172,20 @@ connection_table_new(int table_size)
be9751
         ct->c[i].c_prev = NULL;
be9751
         ct->c[i].c_ci = i;
be9751
         ct->c[i].c_fdi = SLAPD_INVALID_SOCKET_INDEX;
be9751
-        /*
be9751
-         * Technically this is a no-op due to calloc, but we should always be
be9751
-         * careful with things like this ....
be9751
-         */
be9751
-        ct->c[i].c_state = CONN_STATE_FREE;
be9751
+
be9751
+        if (pthread_mutex_init(&(ct->c[i].c_mutex), &monitor_attr) != 0) {
be9751
+            slapi_log_err(SLAPI_LOG_ERR, "connection_table_get_connection", "pthread_mutex_init failed\n");
be9751
+            exit(1);
be9751
+        }
be9751
+
be9751
+        ct->c[i].c_pdumutex = PR_NewLock();
be9751
+        if (ct->c[i].c_pdumutex == NULL) {
be9751
+            slapi_log_err(SLAPI_LOG_ERR, "connection_table_get_connection", "PR_NewLock failed\n");
be9751
+            exit(1);
be9751
+        }
be9751
+
be9751
+        /* Ready to rock, mark as such. */
be9751
+        ct->c[i].c_state = CONN_STATE_INIT;
be9751
         /* Prepare the connection into the freelist. */
be9751
         ct->c_freelist[i] = &(ct->c[i]);
be9751
     }
be9751
@@ -241,44 +261,32 @@ connection_table_get_connection(Connection_Table *ct, int sd)
be9751
             /* Never use slot 0 */
be9751
             ct->conn_next_offset += 1;
be9751
         }
be9751
-        /* Now prep the slot for usage. */
be9751
-        PR_ASSERT(c->c_next == NULL);
be9751
-        PR_ASSERT(c->c_prev == NULL);
be9751
-        PR_ASSERT(c->c_extension == NULL);
be9751
-
be9751
-        if (c->c_state == CONN_STATE_FREE) {
be9751
-
be9751
-            c->c_state = CONN_STATE_INIT;
be9751
-
be9751
-            pthread_mutexattr_t monitor_attr = {0};
be9751
-            pthread_mutexattr_init(&monitor_attr);
be9751
-            pthread_mutexattr_settype(&monitor_attr, PTHREAD_MUTEX_RECURSIVE);
be9751
-            if (pthread_mutex_init(&(c->c_mutex), &monitor_attr) != 0) {
be9751
-                slapi_log_err(SLAPI_LOG_ERR, "connection_table_get_connection", "pthread_mutex_init failed\n");
be9751
-                exit(1);
be9751
-            }
be9751
-
be9751
-            c->c_pdumutex = PR_NewLock();
be9751
-            if (c->c_pdumutex == NULL) {
be9751
-                c->c_pdumutex = NULL;
be9751
-                slapi_log_err(SLAPI_LOG_ERR, "connection_table_get_connection", "PR_NewLock failed\n");
be9751
-                exit(1);
be9751
-            }
be9751
-        }
be9751
-        /* Let's make sure there's no cruft left on there from the last time this connection was used. */
be9751
-        /* Note: no need to lock c->c_mutex because this function is only
be9751
-         * called by one thread (the slapd_daemon thread), and if we got this
be9751
-         * far then `c' is not being used by any operation threads, etc.
be9751
-         */
be9751
-        connection_cleanup(c);
be9751
-        c->c_ct = ct; /* pointer to connection table that owns this connection */
be9751
+        PR_Unlock(ct->table_mutex);
be9751
     } else {
be9751
-        /* couldn't find a Connection */
be9751
+        /* couldn't find a Connection, table must be full */
be9751
         slapi_log_err(SLAPI_LOG_CONNS, "connection_table_get_connection", "Max open connections reached\n");
be9751
+        PR_Unlock(ct->table_mutex);
be9751
+        return NULL;
be9751
     }
be9751
 
be9751
-    /* We could move this to before the c alloc as there is no point to remain here. */
be9751
-    PR_Unlock(ct->table_mutex);
be9751
+    /* Now prep the slot for usage. */
be9751
+    PR_ASSERT(c != NULL);
be9751
+    PR_ASSERT(c->c_next == NULL);
be9751
+    PR_ASSERT(c->c_prev == NULL);
be9751
+    PR_ASSERT(c->c_extension == NULL);
be9751
+    PR_ASSERT(c->c_state == CONN_STATE_INIT);
be9751
+    /* Let's make sure there's no cruft left on there from the last time this connection was used. */
be9751
+
be9751
+    /*
be9751
+     * Note: no need to lock c->c_mutex because this function is only
be9751
+     * called by one thread (the slapd_daemon thread), and if we got this
be9751
+     * far then `c' is not being used by any operation threads, etc. The
be9751
+     * memory ordering will be provided by the work queue sending c to a
be9751
+     * thread.
be9751
+     */
be9751
+    connection_cleanup(c);
be9751
+    /* pointer to connection table that owns this connection */
be9751
+    c->c_ct = ct;
be9751
 
be9751
     return c;
be9751
 }
be9751
-- 
be9751
2.26.2
be9751