Blame SOURCES/0072-Ticket-48192-Individual-abandoned-simple-paged-resul.patch

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