andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From 3b7fb4319f050f4e10593138d6b352cc09c5aad5 Mon Sep 17 00:00:00 2001
dc8c34
From: Noriko Hosoi <nhosoi@redhat.com>
dc8c34
Date: Thu, 4 Jun 2015 16:27:05 -0700
dc8c34
Subject: [PATCH 332/333] Ticket #48192 - Individual abandoned simple paged
dc8c34
 results request has no chance to be cleaned up
dc8c34
dc8c34
Description: When allocating a slot in simple paged results array stashed
dc8c34
in a connection in pagedresults_parse_control_value, a new code is added
dc8c34
to scan the array if the existing slot is timed out or not.  If it is, the
dc8c34
slot is released and a search results is released if it is attached.
dc8c34
dc8c34
Also, if a request is abandoned, instead of returning a valid cookie, it
dc8c34
changed to return an empty cookie to inform the client the request was not
dc8c34
successfully completed.
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/48192
dc8c34
dc8c34
Reviewed by rmeggins@redhat.com (Thank you, Rich!!)
dc8c34
dc8c34
(cherry picked from commit 9035617b50cec984a8ccfea5a0f37d4d0b11f9cd)
dc8c34
---
dc8c34
 ldap/servers/slapd/opshared.c     |  41 +++++++-------
dc8c34
 ldap/servers/slapd/pagedresults.c | 110 ++++++++++++++++++++++++--------------
dc8c34
 2 files changed, 89 insertions(+), 62 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
dc8c34
index d446f50..7b160dd 100644
dc8c34
--- a/ldap/servers/slapd/opshared.c
dc8c34
+++ b/ldap/servers/slapd/opshared.c
dc8c34
@@ -510,8 +510,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
           rc = pagedresults_parse_control_value(pb, ctl_value, &pagesize, &pr_idx, be);
dc8c34
           /* Let's set pr_idx even if it fails; in case, pr_idx == -1. */
dc8c34
           slapi_pblock_set(pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx);
dc8c34
-          if ((LDAP_SUCCESS == rc) ||
dc8c34
-              (LDAP_CANCELLED == rc) || (0 == pagesize)) {
dc8c34
+          if ((LDAP_SUCCESS == rc) || (LDAP_CANCELLED == rc) || (0 == pagesize)) {
dc8c34
               unsigned int opnote = SLAPI_OP_NOTE_SIMPLEPAGED;
dc8c34
               op_set_pagedresults(operation);
dc8c34
               pr_be = pagedresults_get_current_be(pb->pb_conn, pr_idx);
dc8c34
@@ -538,9 +537,8 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
               }
dc8c34
               slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
dc8c34
               if ((LDAP_CANCELLED == rc) || (0 == pagesize)) {
dc8c34
-                  /* paged-results-request was abandoned */
dc8c34
-                  pagedresults_set_response_control(pb, 0, estimate, 
dc8c34
-                                                    curr_search_count, pr_idx);
dc8c34
+                  /* paged-results-request was abandoned; making an empty cookie. */
dc8c34
+                  pagedresults_set_response_control(pb, 0, estimate, -1, pr_idx);
dc8c34
                   send_ldap_result(pb, 0, NULL,
dc8c34
                                    "Simple Paged Results Search abandoned",
dc8c34
                                    0, NULL);
dc8c34
@@ -567,10 +565,21 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
 
dc8c34
       /* adjust time and size limits */
dc8c34
       compute_limits (pb);
dc8c34
-    
dc8c34
-      /* call the pre-search plugins. if they succeed, call the backend 
dc8c34
-     search function. then call the post-search plugins. */
dc8c34
 
dc8c34
+      /* set the timelimit to clean up the too-long-lived-paged results requests */
dc8c34
+      if (op_is_pagedresults(operation)) {
dc8c34
+        time_t optime, time_up;
dc8c34
+        int tlimit;
dc8c34
+        slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &tlimit );
dc8c34
+        slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
dc8c34
+        time_up = (tlimit==-1 ? -1 : optime + tlimit); /* -1: no time limit */
dc8c34
+        pagedresults_set_timelimit(pb->pb_conn, pb->pb_op, time_up, pr_idx);
dc8c34
+      }
dc8c34
+    
dc8c34
+      /*
dc8c34
+       * call the pre-search plugins. if they succeed, call the backend 
dc8c34
+       * search function. then call the post-search plugins.
dc8c34
+       */
dc8c34
       /* ONREPL - should regular plugin be called for internal searches ? */
dc8c34
       if (plugin_call_plugins(pb, SLAPI_PLUGIN_PRE_SEARCH_FN) == 0)
dc8c34
       {
dc8c34
@@ -635,16 +644,6 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
     }
dc8c34
   }
dc8c34
 
dc8c34
-  /* set the timelimit to clean up the too-long-lived-paged results requests */
dc8c34
-  if (op_is_pagedresults(operation)) {
dc8c34
-    time_t optime, time_up;
dc8c34
-    int tlimit;
dc8c34
-    slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &tlimit );
dc8c34
-    slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
dc8c34
-    time_up = (tlimit==-1 ? -1 : optime + tlimit); /* -1: no time limit */
dc8c34
-    pagedresults_set_timelimit(pb->pb_conn, pb->pb_op, time_up, pr_idx);
dc8c34
-  }
dc8c34
-
dc8c34
   /* PAR: now filters have been rewritten, we can assign plugins to work on them */
dc8c34
   index_subsys_assign_filter_decoders(pb);
dc8c34
 
dc8c34
@@ -873,10 +872,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
             slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET, &sr);
dc8c34
             if (PAGEDRESULTS_SEARCH_END == pr_stat) {
dc8c34
               if (sr) { /* in case a left over sr is found, clean it up */
dc8c34
-                PR_Lock(pb->pb_conn->c_mutex);
dc8c34
-                pagedresults_set_search_result(pb->pb_conn, operation, NULL, 1, pr_idx);
dc8c34
-                be->be_search_results_release(&sr);
dc8c34
-                PR_Unlock(pb->pb_conn->c_mutex);
dc8c34
+                pagedresults_free_one(pb->pb_conn, operation, pr_idx);
dc8c34
               }
dc8c34
               if (NULL == next_be) {
dc8c34
                 /* no more entries && no more backends */
dc8c34
@@ -1299,7 +1295,6 @@ iterate(Slapi_PBlock *pb, Slapi_Backend *be, int send_result,
dc8c34
                 operation_out_of_disk_space();
dc8c34
             }
dc8c34
             pr_stat = PAGEDRESULTS_SEARCH_END;
dc8c34
-            pagedresults_set_timelimit(pb->pb_conn, pb->pb_op, 0, pr_idx);
dc8c34
             rval = -1;
dc8c34
             done = 1;
dc8c34
             continue;
dc8c34
diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c
dc8c34
index 327da54..402dd10 100644
dc8c34
--- a/ldap/servers/slapd/pagedresults.c
dc8c34
+++ b/ldap/servers/slapd/pagedresults.c
dc8c34
@@ -41,6 +41,27 @@
dc8c34
 
dc8c34
 #include "slap.h"
dc8c34
 
dc8c34
+/* helper function to clean up one prp slot */
dc8c34
+static void
dc8c34
+_pr_cleanup_one_slot(PagedResults *prp)
dc8c34
+{
dc8c34
+    PRLock *prmutex = NULL;
dc8c34
+    if (!prp) {
dc8c34
+        return;
dc8c34
+    }
dc8c34
+    if (prp->pr_current_be && prp->pr_current_be->be_search_results_release) {
dc8c34
+        /* sr is left; release it. */
dc8c34
+        prp->pr_current_be->be_search_results_release(&(prp->pr_search_result_set));
dc8c34
+    }
dc8c34
+    /* clean up the slot */
dc8c34
+    if (prp->pr_mutex) {
dc8c34
+        /* pr_mutex is reused; back it up and reset it. */
dc8c34
+        prmutex = prp->pr_mutex;
dc8c34
+    }
dc8c34
+    memset(prp, '\0', sizeof(PagedResults));
dc8c34
+    prp->pr_mutex = prmutex;
dc8c34
+}
dc8c34
+
dc8c34
 /*
dc8c34
  * Parse the value from an LDAPv3 "Simple Paged Results" control.  They look
dc8c34
  * like this:
dc8c34
@@ -65,6 +86,7 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
     Connection *conn = pb->pb_conn;
dc8c34
     Operation *op = pb->pb_op;
dc8c34
     BerElement *ber = NULL;
dc8c34
+    PagedResults *prp = NULL;
dc8c34
 
dc8c34
     LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_parse_control_value\n");
dc8c34
     if ( NULL == conn || NULL == op || NULL == pagesize || NULL == index ) {
dc8c34
@@ -117,13 +139,31 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
             }
dc8c34
             *index = maxlen; /* the first position in the new area */
dc8c34
         } else {
dc8c34
-            for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) {
dc8c34
-                if (!conn->c_pagedresults.prl_list[i].pr_current_be) {
dc8c34
-                    conn->c_pagedresults.prl_list[i].pr_current_be = be;
dc8c34
+            time_t ctime = current_time();
dc8c34
+            prp = conn->c_pagedresults.prl_list;
dc8c34
+            for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++, prp++) {
dc8c34
+                if (!prp->pr_current_be) { /* unused slot; take it */
dc8c34
+                    prp->pr_current_be = be;
dc8c34
+                    *index = i;
dc8c34
+                    break;
dc8c34
+                } else if (((prp->pr_timelimit > 0) && (ctime < prp->pr_timelimit)) || /* timelimit exceeded */
dc8c34
+                           (prp->pr_flags & CONN_FLAG_PAGEDRESULTS_ABANDONED) /* abandoned */) {
dc8c34
+                    _pr_cleanup_one_slot(prp);
dc8c34
+                    conn->c_pagedresults.prl_count--;
dc8c34
+                    prp->pr_current_be = be;
dc8c34
                     *index = i;
dc8c34
                     break;
dc8c34
                 }
dc8c34
             }
dc8c34
+            /* cleaning up the rest of the timedout if any */
dc8c34
+            for (++i; i < conn->c_pagedresults.prl_maxlen; i++, prp++) {
dc8c34
+                if (prp->pr_current_be &&
dc8c34
+                    (((prp->pr_timelimit > 0) && (ctime < prp->pr_timelimit)) || /* timelimit exceeded */
dc8c34
+                    (prp->pr_flags & CONN_FLAG_PAGEDRESULTS_ABANDONED)) /* abandoned */) {
dc8c34
+                    _pr_cleanup_one_slot(prp);
dc8c34
+                    conn->c_pagedresults.prl_count--;
dc8c34
+                }
dc8c34
+            }
dc8c34
         }
dc8c34
         if ((*index > -1) && (*index < conn->c_pagedresults.prl_maxlen) &&
dc8c34
             !conn->c_pagedresults.prl_list[*index].pr_mutex) {
dc8c34
@@ -131,7 +171,6 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
         }
dc8c34
         conn->c_pagedresults.prl_count++;
dc8c34
     } else {
dc8c34
-        PagedResults *prp = NULL;
dc8c34
         /* Repeated paged results request.
dc8c34
          * PagedResults is already allocated. */
dc8c34
         char *ptr = slapi_ch_malloc(cookie.bv_len + 1);
dc8c34
@@ -156,8 +195,10 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
     slapi_ch_free((void **)&cookie.bv_val);
dc8c34
 
dc8c34
     if ((*index > -1) && (*index < conn->c_pagedresults.prl_maxlen)) {
dc8c34
-        if (conn->c_pagedresults.prl_list[*index].pr_flags &
dc8c34
-            CONN_FLAG_PAGEDRESULTS_ABANDONED) {
dc8c34
+        if (conn->c_pagedresults.prl_list[*index].pr_flags & CONN_FLAG_PAGEDRESULTS_ABANDONED) {
dc8c34
+            /* repeated case? */
dc8c34
+            prp = conn->c_pagedresults.prl_list + *index;
dc8c34
+            _pr_cleanup_one_slot(prp);
dc8c34
             rc = LDAP_CANCELLED;
dc8c34
         } else {
dc8c34
             /* Need to keep the latest msgid to prepare for the abandon. */
dc8c34
@@ -273,20 +314,8 @@ pagedresults_free_one( Connection *conn, Operation *op, int index )
dc8c34
                            "conn=%d paged requests list count is %d\n",
dc8c34
                            conn->c_connid, conn->c_pagedresults.prl_count);
dc8c34
         } else if (index < conn->c_pagedresults.prl_maxlen) {
dc8c34
-            PRLock *prmutex = NULL;
dc8c34
             PagedResults *prp = conn->c_pagedresults.prl_list + index;
dc8c34
-            if (prp && prp->pr_current_be &&
dc8c34
-                prp->pr_current_be->be_search_results_release &&
dc8c34
-                prp->pr_search_result_set) {
dc8c34
-                prp->pr_current_be->be_search_results_release(&(prp->pr_search_result_set));
dc8c34
-            }
dc8c34
-            prp->pr_current_be = NULL;
dc8c34
-            if (prp->pr_mutex) {
dc8c34
-                /* pr_mutex is reused; back it up and reset it. */
dc8c34
-                prmutex = prp->pr_mutex;
dc8c34
-            }
dc8c34
-            memset(prp, '\0', sizeof(PagedResults));
dc8c34
-            prp->pr_mutex = prmutex;
dc8c34
+            _pr_cleanup_one_slot(prp);
dc8c34
             conn->c_pagedresults.prl_count--;
dc8c34
             rc = 0;
dc8c34
         }
dc8c34
@@ -309,7 +338,7 @@ pagedresults_free_one_msgid_nolock( Connection *conn, ber_int_t msgid )
dc8c34
             ; /* Not a paged result. */
dc8c34
         } else {
dc8c34
             LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
-                          "--> pagedresults_free_one: msgid=%d\n", msgid);
dc8c34
+                          "--> pagedresults_free_one_msgid_nolock: msgid=%d\n", msgid);
dc8c34
             for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) {
dc8c34
                 if (conn->c_pagedresults.prl_list[i].pr_msgid == msgid) {
dc8c34
                     PagedResults *prp = conn->c_pagedresults.prl_list + i;
dc8c34
@@ -318,16 +347,14 @@ pagedresults_free_one_msgid_nolock( Connection *conn, ber_int_t msgid )
dc8c34
                         prp->pr_search_result_set) {
dc8c34
                         prp->pr_current_be->be_search_results_release(&(prp->pr_search_result_set));
dc8c34
                     }
dc8c34
-                    prp->pr_current_be = NULL;
dc8c34
                     prp->pr_flags |= CONN_FLAG_PAGEDRESULTS_ABANDONED;
dc8c34
                     prp->pr_flags &= ~CONN_FLAG_PAGEDRESULTS_PROCESSING;
dc8c34
-                    conn->c_pagedresults.prl_count--;
dc8c34
                     rc = 0;
dc8c34
                     break;
dc8c34
                 }
dc8c34
             }
dc8c34
             LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
-                          "<-- pagedresults_free_one: %d\n", rc);
dc8c34
+                          "<-- pagedresults_free_one_msgid_nolock: %d\n", rc);
dc8c34
         }
dc8c34
     }
dc8c34
 
dc8c34
@@ -845,37 +872,42 @@ pagedresults_reset_processing(Connection *conn, int index)
dc8c34
 }
dc8c34
 #endif
dc8c34
 
dc8c34
-/* Are all the paged results requests timed out? */
dc8c34
+/*
dc8c34
+ * This timedout is mainly for an end user leaves a commandline untouched
dc8c34
+ * for a long time.  This should not affect a permanent connection which
dc8c34
+ * manages multiple simple paged results requests over the connection.
dc8c34
+ *
dc8c34
+ * [rule]
dc8c34
+ * If there is just one slot and it's timed out, we return it is timedout.
dc8c34
+ * If there are multiple slots, the connection may be a permanent one.
dc8c34
+ * Do not return timed out here.  But let the next request take care the
dc8c34
+ * timedout slot(s).
dc8c34
+ */
dc8c34
 int
dc8c34
 pagedresults_is_timedout_nolock(Connection *conn)
dc8c34
 {
dc8c34
-    int i;
dc8c34
     PagedResults *prp = NULL;
dc8c34
     time_t ctime;
dc8c34
-    int rc = 0;
dc8c34
 
dc8c34
     LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_is_timedout\n");
dc8c34
 
dc8c34
-    if (NULL == conn || 0 == conn->c_pagedresults.prl_count) {
dc8c34
-        LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_is_timedout: -\n");
dc8c34
-        return rc;
dc8c34
+    if (!conn || (0 == conn->c_pagedresults.prl_maxlen)) {
dc8c34
+        LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_is_timedout: false\n");
dc8c34
+        return 0;
dc8c34
     }
dc8c34
 
dc8c34
     ctime = current_time();
dc8c34
-    for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) {
dc8c34
-        prp = conn->c_pagedresults.prl_list + i;
dc8c34
+    prp = conn->c_pagedresults.prl_list;
dc8c34
+    if (prp && (1 == conn->c_pagedresults.prl_maxlen)) {
dc8c34
         if (prp->pr_current_be && (prp->pr_timelimit > 0)) {
dc8c34
-            if (ctime < prp->pr_timelimit) {
dc8c34
-                LDAPDebug0Args(LDAP_DEBUG_TRACE,
dc8c34
-                               "<-- pagedresults_is_timedout: 0\n");
dc8c34
-                return 0; /* at least, one request is not timed out. */
dc8c34
-            } else {
dc8c34
-                rc = 1;   /* possibly timed out */
dc8c34
+            if (ctime > prp->pr_timelimit) {
dc8c34
+                LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_is_timedout: true\n");
dc8c34
+                return 1;
dc8c34
             }
dc8c34
         }
dc8c34
     }
dc8c34
-    LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_is_timedout: 1\n");
dc8c34
-    return rc; /* all requests are timed out. */
dc8c34
+    LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_is_timedout: false\n");
dc8c34
+    return 0;
dc8c34
 }
dc8c34
 
dc8c34
 /* reset all timeout */
dc8c34
-- 
dc8c34
1.9.3
dc8c34