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

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