andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From 15fb6cdf070453ee9daf4a4eba92420dc4a7a076 Mon Sep 17 00:00:00 2001
dc8c34
From: Noriko Hosoi <nhosoi@redhat.com>
dc8c34
Date: Tue, 9 Jun 2015 10:02:02 -0700
dc8c34
Subject: [PATCH] Ticket #48192 - Individual abandoned simple paged results
dc8c34
 request has no chance to be cleaned up
dc8c34
dc8c34
Description: When a simple paged results is abandoned immediately and
dc8c34
asynchronously just after the request, the abandon request has a chance
dc8c34
to be handled before the simple paged results control is received and
dc8c34
processed.  In the case, the search could be executed and the search
dc8c34
result structure could be leaked.
dc8c34
dc8c34
This patch adds more abandon checks.  In op_shared_search, after the
dc8c34
send_results_ext call, if the SLAPI_OP_STATUS_ABANDONED bit is set in
dc8c34
the status in the operation object, it cleans up the search results
dc8c34
again, which gives the second chance.
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/48192
dc8c34
dc8c34
Reviewed by tbordaz@redhat.com (Thank you so much, Thierry!!)
dc8c34
dc8c34
(cherry picked from commit 1d18dd0107d48ac1d79f7c9988adf18b0905bbdb)
dc8c34
(cherry picked from commit 798eae4f2240a5b47963a2bb09a2a17acfc488ec)
dc8c34
(cherry picked from commit 16a8ef16724f1f657366169a7fd0ae1686b61d4b)
dc8c34
---
dc8c34
 ldap/servers/slapd/abandon.c               | 10 +++---
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_search.c | 13 ++++++--
dc8c34
 ldap/servers/slapd/opshared.c              | 36 +++++++++++++--------
dc8c34
 ldap/servers/slapd/pagedresults.c          | 52 +++++++++++++++++-------------
dc8c34
 ldap/servers/slapd/proto-slap.h            |  2 +-
dc8c34
 5 files changed, 69 insertions(+), 44 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/slapd/abandon.c b/ldap/servers/slapd/abandon.c
dc8c34
index 9639701..09da149 100644
dc8c34
--- a/ldap/servers/slapd/abandon.c
dc8c34
+++ b/ldap/servers/slapd/abandon.c
dc8c34
@@ -132,8 +132,7 @@ do_abandon( Slapi_PBlock *pb )
dc8c34
 		}
dc8c34
 
dc8c34
 		operation_set_abandoned_op (pb->pb_op, o->o_abandoned_op);
dc8c34
-		if ( plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_ABANDON_FN )
dc8c34
-		    == 0 ) {
dc8c34
+		if ( plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_ABANDON_FN ) == 0 ) {
dc8c34
 			int	rc = 0;
dc8c34
 
dc8c34
 			if ( o->o_status != SLAPI_OP_STATUS_RESULT_SENT ) {
dc8c34
@@ -148,14 +147,13 @@ do_abandon( Slapi_PBlock *pb )
dc8c34
 			suppressed_by_plugin = 1;
dc8c34
 		}
dc8c34
 	} else {
dc8c34
-		LDAPDebug( LDAP_DEBUG_TRACE, "do_abandon: op not found\n", 0, 0,
dc8c34
-		    0 );
dc8c34
+		LDAPDebug0Args(LDAP_DEBUG_TRACE, "do_abandon: op not found\n");
dc8c34
 	}
dc8c34
 
dc8c34
 	if ( 0 == pagedresults_free_one_msgid_nolock(pb->pb_conn, id) ) {
dc8c34
 		slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 
dc8c34
-		                  " op=%d ABANDON targetop=Simple Paged Results\n",
dc8c34
-		                  pb->pb_conn->c_connid, pb->pb_op->o_opid );
dc8c34
+		    " op=%d ABANDON targetop=Simple Paged Results msgid=%d\n",
dc8c34
+		    pb->pb_conn->c_connid, pb->pb_op->o_opid, id );
dc8c34
 	} else if ( NULL == o ) {
dc8c34
 		slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d ABANDON"
dc8c34
 			" targetop=NOTFOUND msgid=%d\n",
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
index b5ba89c..92ae691 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
@@ -1807,12 +1807,21 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
dc8c34
           }
dc8c34
         }
dc8c34
     }
dc8c34
+    /* check for the final abandon */
dc8c34
+    if (slapi_op_abandoned(pb)) {
dc8c34
+        slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET_SIZE_ESTIMATE, &estimate );
dc8c34
+        if ( use_extension ) {
dc8c34
+            slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, NULL );
dc8c34
+        }
dc8c34
+        slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
dc8c34
+        delete_search_result_set(pb, &sr);
dc8c34
+        rc = SLAPI_FAIL_GENERAL;
dc8c34
+    }
dc8c34
 
dc8c34
 bail:
dc8c34
-    if(rc && op) {
dc8c34
+    if (rc && op) {
dc8c34
         op->o_reverse_search_state = 0;
dc8c34
     }
dc8c34
-
dc8c34
     return rc;
dc8c34
 }
dc8c34
 
dc8c34
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
dc8c34
index 7b160dd..28fe066 100644
dc8c34
--- a/ldap/servers/slapd/opshared.c
dc8c34
+++ b/ldap/servers/slapd/opshared.c
dc8c34
@@ -741,7 +741,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
         pagedresults_unlock(pb->pb_conn, pr_idx);
dc8c34
         if (next_be) {
dc8c34
           /* no more entries, but at least another backend */
dc8c34
-          if (pagedresults_set_current_be(pb->pb_conn, next_be, pr_idx) < 0) {
dc8c34
+          if (pagedresults_set_current_be(pb->pb_conn, next_be, pr_idx, 0) < 0) {
dc8c34
               goto free_and_return;
dc8c34
           }
dc8c34
         }
dc8c34
@@ -871,23 +871,23 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
             curr_search_count = pnentries;
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
-                pagedresults_free_one(pb->pb_conn, operation, pr_idx);
dc8c34
-              }
dc8c34
+              /* no more entries, but at least another backend */
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
+              rc = pagedresults_set_current_be(pb->pb_conn, next_be, pr_idx, 1);
dc8c34
+              PR_Unlock(pb->pb_conn->c_mutex);
dc8c34
               if (NULL == next_be) {
dc8c34
-                /* no more entries && no more backends */
dc8c34
-                curr_search_count = -1;
dc8c34
-              } else {
dc8c34
-                /* no more entries, but at least another backend */
dc8c34
-                if (pagedresults_set_current_be(pb->pb_conn, next_be, pr_idx) < 0) {
dc8c34
+                  /* no more entries && no more backends */
dc8c34
+                  curr_search_count = -1;
dc8c34
+              } else if (rc < 0) {
dc8c34
                   goto free_and_return;
dc8c34
-                }
dc8c34
               }
dc8c34
             } else {
dc8c34
               curr_search_count = pnentries;
dc8c34
               slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET_SIZE_ESTIMATE, &estimate);
dc8c34
               pagedresults_lock(pb->pb_conn, pr_idx);
dc8c34
-              if ((pagedresults_set_current_be(pb->pb_conn, be, pr_idx) < 0) ||
dc8c34
+              if ((pagedresults_set_current_be(pb->pb_conn, be, pr_idx, 0) < 0) ||
dc8c34
                   (pagedresults_set_search_result(pb->pb_conn, operation, sr, 0, pr_idx) < 0) ||
dc8c34
                   (pagedresults_set_search_result_count(pb->pb_conn, operation, curr_search_count, pr_idx) < 0) ||
dc8c34
                   (pagedresults_set_search_result_set_size_estimate(pb->pb_conn, operation, estimate, pr_idx) < 0) ||
dc8c34
@@ -897,10 +897,20 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
               }
dc8c34
               pagedresults_unlock(pb->pb_conn, pr_idx);
dc8c34
             }
dc8c34
-            pagedresults_set_response_control(pb, 0, estimate, 
dc8c34
-                                              curr_search_count, pr_idx);
dc8c34
             slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
dc8c34
             next_be = NULL; /* to break the loop */
dc8c34
+            if (operation->o_status & SLAPI_OP_STATUS_ABANDONED) {
dc8c34
+                /* It turned out this search was abandoned. */
dc8c34
+                PR_Lock(pb->pb_conn->c_mutex);
dc8c34
+                pagedresults_free_one_msgid_nolock( pb->pb_conn, operation->o_msgid);
dc8c34
+                PR_Unlock(pb->pb_conn->c_mutex);
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, "Simple Paged Results Search abandoned", 0, NULL);
dc8c34
+                rc = LDAP_SUCCESS;
dc8c34
+                goto free_and_return;
dc8c34
+            }
dc8c34
+            pagedresults_set_response_control(pb, 0, estimate, curr_search_count, pr_idx);
dc8c34
             if (curr_search_count == -1) {
dc8c34
                 pagedresults_free_one(pb->pb_conn, operation, pr_idx);
dc8c34
             }
dc8c34
diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c
dc8c34
index 2e70e19..a7fe2cd 100644
dc8c34
--- a/ldap/servers/slapd/pagedresults.c
dc8c34
+++ b/ldap/servers/slapd/pagedresults.c
dc8c34
@@ -87,6 +87,8 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
     Operation *op = pb->pb_op;
dc8c34
     BerElement *ber = NULL;
dc8c34
     PagedResults *prp = NULL;
dc8c34
+    time_t ctime = current_time();
dc8c34
+    int i;
dc8c34
 
dc8c34
     LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_parse_control_value\n");
dc8c34
     if ( NULL == conn || NULL == op || NULL == pagesize || NULL == index ) {
dc8c34
@@ -121,7 +123,6 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
     /* the ber encoding is no longer needed */
dc8c34
     ber_free(ber, 1);
dc8c34
     if ( cookie.bv_len <= 0 ) {
dc8c34
-        int i;
dc8c34
         /* first time? */
dc8c34
         int maxlen = conn->c_pagedresults.prl_maxlen;
dc8c34
         if (conn->c_pagedresults.prl_count == maxlen) {
dc8c34
@@ -138,15 +139,16 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
                 memset(conn->c_pagedresults.prl_list + maxlen, '\0', sizeof(PagedResults) * maxlen);
dc8c34
             }
dc8c34
             *index = maxlen; /* the first position in the new area */
dc8c34
+            prp = conn->c_pagedresults.prl_list + *index;
dc8c34
+            prp->pr_current_be = be;
dc8c34
         } else {
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
+                } 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
@@ -155,15 +157,6 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
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
@@ -181,8 +174,8 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
         if ((conn->c_pagedresults.prl_maxlen <= *index) || (*index < 0)){
dc8c34
             rc = LDAP_PROTOCOL_ERROR;
dc8c34
             LDAPDebug1Arg(LDAP_DEBUG_ANY,
dc8c34
-                          "pagedresults_parse_control_value: invalid cookie: %d\n",
dc8c34
-                          *index);
dc8c34
+                          "pagedresults_parse_control_value: invalid cookie: %d\n", *index);
dc8c34
+            *index = -1; /* index is invalid. reinitializing it. */
dc8c34
             goto bail;
dc8c34
         }
dc8c34
         prp = conn->c_pagedresults.prl_list + *index;
dc8c34
@@ -206,11 +199,24 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
         }
dc8c34
     } else {
dc8c34
         rc = LDAP_PROTOCOL_ERROR;
dc8c34
-        LDAPDebug1Arg(LDAP_DEBUG_ANY,
dc8c34
-                      "pagedresults_parse_control_value: invalid cookie: %d\n",
dc8c34
-                      *index);
dc8c34
+        LDAPDebug1Arg(LDAP_DEBUG_ANY, "pagedresults_parse_control_value: invalid cookie: %d\n", *index);
dc8c34
     }
dc8c34
 bail:
dc8c34
+    /* cleaning up the rest of the timedout or abandoned if any */
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 &&
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
+            if (i == *index) {
dc8c34
+                /* registered slot is expired and cleaned up. return cancelled. */
dc8c34
+                *index = -1;
dc8c34
+                rc = LDAP_CANCELLED;
dc8c34
+            }
dc8c34
+        }
dc8c34
+    }
dc8c34
     PR_Unlock(conn->c_mutex);
dc8c34
 
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
@@ -326,7 +332,9 @@ pagedresults_free_one( Connection *conn, Operation *op, int index )
dc8c34
     return rc;
dc8c34
 }
dc8c34
 
dc8c34
-/* Used for abandoning */
dc8c34
+/* 
dc8c34
+ * Used for abandoning - conn->c_mutex is already locked in do_abandone.
dc8c34
+ */
dc8c34
 int 
dc8c34
 pagedresults_free_one_msgid_nolock( Connection *conn, ber_int_t msgid )
dc8c34
 {
dc8c34
@@ -334,7 +342,7 @@ pagedresults_free_one_msgid_nolock( Connection *conn, ber_int_t msgid )
dc8c34
     int i;
dc8c34
 
dc8c34
     if (conn && (msgid > -1)) {
dc8c34
-        if (conn->c_pagedresults.prl_count <= 0) {
dc8c34
+        if (conn->c_pagedresults.prl_maxlen <= 0) {
dc8c34
             ; /* Not a paged result. */
dc8c34
         } else {
dc8c34
             LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
@@ -381,18 +389,18 @@ pagedresults_get_current_be(Connection *conn, int index)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_set_current_be(Connection *conn, Slapi_Backend *be, int index)
dc8c34
+pagedresults_set_current_be(Connection *conn, Slapi_Backend *be, int index, int nolock)
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_set_current_be: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
-        PR_Lock(conn->c_mutex);
dc8c34
+        if (!nolock) PR_Lock(conn->c_mutex);
dc8c34
         if (index < conn->c_pagedresults.prl_maxlen) {
dc8c34
             conn->c_pagedresults.prl_list[index].pr_current_be = be;
dc8c34
         }
dc8c34
-        PR_Unlock(conn->c_mutex);
dc8c34
         rc = 0;
dc8c34
+        if (!nolock) PR_Unlock(conn->c_mutex);
dc8c34
     }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "<-- pagedresults_set_current_be: %d\n", rc);
dc8c34
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
dc8c34
index 4c3c29d..55d53bd 100644
dc8c34
--- a/ldap/servers/slapd/proto-slap.h
dc8c34
+++ b/ldap/servers/slapd/proto-slap.h
dc8c34
@@ -1437,7 +1437,7 @@ void pagedresults_set_response_control(Slapi_PBlock *pb, int iscritical,
dc8c34
                                        ber_int_t estimate,
dc8c34
                                        int curr_search_count, int index);
dc8c34
 Slapi_Backend *pagedresults_get_current_be(Connection *conn, int index);
dc8c34
-int pagedresults_set_current_be(Connection *conn, Slapi_Backend *be, int index);
dc8c34
+int pagedresults_set_current_be(Connection *conn, Slapi_Backend *be, int index, int nolock);
dc8c34
 void *pagedresults_get_search_result(Connection *conn, Operation *op,
dc8c34
                                      int index);
dc8c34
 int pagedresults_set_search_result(Connection *conn, Operation *op, void *sr, 
dc8c34
-- 
dc8c34
1.9.3
dc8c34