andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From 3efa97aae09f5228bff773809c35db30fa602dfd Mon Sep 17 00:00:00 2001
dc8c34
From: Noriko Hosoi <nhosoi@redhat.com>
dc8c34
Date: Fri, 26 Apr 2013 15:24:22 -0700
dc8c34
Subject: [PATCH 58/99] Ticket #47347 - Simple paged results should support
dc8c34
 async search
dc8c34
dc8c34
Bug description: Simple paged results serialized the request
dc8c34
even for a series of asynchronous search requests, and it
dc8c34
returned error 53 (unwilling to perform) if the second request
dc8c34
comes in while the first one is being processed.
dc8c34
dc8c34
Fix description: This patch implements the asynchronous support
dc8c34
for the Simple paged results search.
dc8c34
- Removed pagedresults_check_or_set_processing which was
dc8c34
  used to Simple paged results requests exclusive.  Instead,
dc8c34
  pagedresults_lock is introduced to protect the PagedResults
dc8c34
  object from the other threads sharing the same cookie.
dc8c34
- If any error including hitting the sizelimit or timelimit,
dc8c34
  search result set was released immediately in ldbm_back_
dc8c34
  next_search_entry_ext, which could cause the race condition
dc8c34
  among multiple asynchronous search requests.  To prevent it,
dc8c34
  the search result set is untouched if the operation is a
dc8c34
  Simple paged result search, and let its clean up function
dc8c34
  to handle it.
dc8c34
- Sizelimit was evaluated in the accumulative way instead of
dc8c34
  on the each page size.  For instance, if the sizelimit was
dc8c34
  101 AND the page size is 100, as soon as getting the 2nd page,
dc8c34
  it hit the sizelimit and the search failed.  This patch fixes
dc8c34
  it so that as long as the requested page size is less than 101,
dc8c34
  the requests successfully continue without getting an error 4
dc8c34
  (LDAP_SIZELIMIT_EXCEEDED).  To fulfill the requirement, the
dc8c34
  current size needs to be managed per operation instead of the
dc8c34
  search result set or PagedResults object. For the purpose,
dc8c34
  introduced o_pagedresults_sizelimit to Slapi_Operation.
dc8c34
- When shutting down, connection_table_free could use backend
dc8c34
  callback (e.g., be_search_results_release). Therefore, moved
dc8c34
  be_cleanupall after connection_table_free.
dc8c34
- Each Simple paged results helper functions checks if the
dc8c34
  operation is really a Simple paged result request control is
dc8c34
  associated with to prevent any unexpected behaviour.
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/47347
dc8c34
dc8c34
Reviewed by Rich (Thank you!!)
dc8c34
(cherry picked from commit d53e8221f77ac325123e3bb4f61cf6de67dce646)
dc8c34
(cherry picked from commit 96535a6756b8a556897fb643a31421c7f5068166)
dc8c34
---
dc8c34
 ldap/servers/slapd/back-ldbm/filterindex.c |  11 +-
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_search.c | 117 ++++++++++----------
dc8c34
 ldap/servers/slapd/back-ldbm/vlv.c         |   2 +-
dc8c34
 ldap/servers/slapd/daemon.c                |  13 ++-
dc8c34
 ldap/servers/slapd/operation.c             |   9 +-
dc8c34
 ldap/servers/slapd/opshared.c              |  85 +++++++++------
dc8c34
 ldap/servers/slapd/pagedresults.c          | 165 ++++++++++++++++++++++++++---
dc8c34
 ldap/servers/slapd/proto-slap.h            |  46 +++++---
dc8c34
 ldap/servers/slapd/slap.h                  |   2 +
dc8c34
 ldap/servers/slapd/sort.c                  |   6 +-
dc8c34
 10 files changed, 320 insertions(+), 136 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/filterindex.c b/ldap/servers/slapd/back-ldbm/filterindex.c
dc8c34
index 27b20ec..995a62e 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/filterindex.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/filterindex.c
dc8c34
@@ -317,7 +317,7 @@ ava_candidates(
dc8c34
         if ( unindexed ) {
dc8c34
             unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
dc8c34
             slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
dc8c34
-            pagedresults_set_unindexed( pb->pb_conn, pr_idx );
dc8c34
+            pagedresults_set_unindexed( pb->pb_conn, pb->pb_op, pr_idx );
dc8c34
         }
dc8c34
 
dc8c34
         /* We don't use valuearray_free here since the valueset, berval
dc8c34
@@ -349,7 +349,7 @@ ava_candidates(
dc8c34
         if ( unindexed ) {
dc8c34
             unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
dc8c34
             slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
dc8c34
-            pagedresults_set_unindexed( pb->pb_conn, pr_idx );
dc8c34
+            pagedresults_set_unindexed( pb->pb_conn, pb->pb_op, pr_idx );
dc8c34
         }
dc8c34
          valuearray_free( &ivals );
dc8c34
          LDAPDebug( LDAP_DEBUG_TRACE, "<= ava_candidates %lu\n",
dc8c34
@@ -390,7 +390,7 @@ presence_candidates(
dc8c34
         unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
dc8c34
         slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
dc8c34
         slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx);
dc8c34
-        pagedresults_set_unindexed( pb->pb_conn, pr_idx );
dc8c34
+        pagedresults_set_unindexed(pb->pb_conn, pb->pb_op, pr_idx);
dc8c34
     }
dc8c34
 
dc8c34
     if (idl != NULL && ALLIDS(idl) && strcasecmp(type, "nscpentrydn") == 0) {
dc8c34
@@ -504,6 +504,7 @@ extensible_candidates(
dc8c34
                                                   SLAPI_PAGED_RESULTS_INDEX,
dc8c34
                                                   &pr_idx );
dc8c34
                                 pagedresults_set_unindexed( glob_pb->pb_conn,
dc8c34
+                                                            glob_pb->pb_op,
dc8c34
                                                             pr_idx );
dc8c34
                             }
dc8c34
                             if (idl2 == NULL)
dc8c34
@@ -916,7 +917,7 @@ substring_candidates(
dc8c34
     slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx);
dc8c34
     if ( ivals == NULL || *ivals == NULL ) {
dc8c34
         slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
dc8c34
-        pagedresults_set_unindexed( pb->pb_conn, pr_idx );
dc8c34
+        pagedresults_set_unindexed( pb->pb_conn, pb->pb_op, pr_idx );
dc8c34
         LDAPDebug( LDAP_DEBUG_TRACE,
dc8c34
             "<= sub_candidates ALLIDS (no keys)\n", 0, 0, 0 );
dc8c34
         return( idl_allids( be ) );
dc8c34
@@ -930,7 +931,7 @@ substring_candidates(
dc8c34
     idl = keys2idl( be, type, indextype_SUB, ivals, err, &unindexed, &txn, allidslimit );
dc8c34
     if ( unindexed ) {
dc8c34
         slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
dc8c34
-        pagedresults_set_unindexed( pb->pb_conn, pr_idx );
dc8c34
+        pagedresults_set_unindexed( pb->pb_conn, pb->pb_op, pr_idx );
dc8c34
     }
dc8c34
     valuearray_free( &ivals );
dc8c34
 
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
index f86f27c..670f627 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
@@ -53,7 +53,7 @@ static int build_candidate_list( Slapi_PBlock *pb, backend *be,
dc8c34
 static IDList *base_candidates( Slapi_PBlock *pb, struct backentry *e );
dc8c34
 static IDList *onelevel_candidates( Slapi_PBlock *pb, backend *be, const char *base, struct backentry *e, Slapi_Filter *filter, int managedsait, int *lookup_returned_allidsp, int *err );
dc8c34
 static back_search_result_set* new_search_result_set(IDList* idl,int vlv, int lookthroughlimit);
dc8c34
-static void delete_search_result_set( back_search_result_set **sr );
dc8c34
+static void delete_search_result_set(Slapi_PBlock *pb, back_search_result_set **sr);
dc8c34
 static int can_skip_filter_test( Slapi_PBlock *pb, struct slapi_filter *f,
dc8c34
         int scope, IDList *idl );
dc8c34
 
dc8c34
@@ -165,6 +165,7 @@ ldbm_back_search_cleanup(Slapi_PBlock *pb,
dc8c34
     int estimate = 0; /* estimated search result count */
dc8c34
     backend *be;
dc8c34
     ldbm_instance *inst;
dc8c34
+    back_search_result_set *sr = NULL;
dc8c34
 
dc8c34
     slapi_pblock_get( pb, SLAPI_BACKEND, &be );
dc8c34
     inst = (ldbm_instance *) be->be_instance_info;
dc8c34
@@ -178,19 +179,14 @@ ldbm_back_search_cleanup(Slapi_PBlock *pb,
dc8c34
     {
dc8c34
         slapi_send_ldap_result( pb, ldap_result, NULL, ldap_result_description, 0, NULL );
dc8c34
     }
dc8c34
-    {
dc8c34
-        /* hack hack --- code to free the result set if we don't need it */
dc8c34
-        /* We get it and check to see if the structure was ever used */
dc8c34
-        back_search_result_set *sr = NULL;
dc8c34
-        slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &sr );
dc8c34
-        if ( (NULL != sr) && (function_result != 0) ) {
dc8c34
-            int pr_idx = -1;
dc8c34
-            slapi_pblock_get( pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx );
dc8c34
-            /* in case paged results, clean up the conn */
dc8c34
-            pagedresults_set_search_result( pb->pb_conn, NULL, 0, pr_idx );
dc8c34
-            slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
dc8c34
-            slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET_SIZE_ESTIMATE, &estimate );
dc8c34
-            delete_search_result_set(&sr);
dc8c34
+    /* code to free the result set if we don't need it */
dc8c34
+    /* We get it and check to see if the structure was ever used */
dc8c34
+    slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET, &sr);
dc8c34
+    if (sr) {
dc8c34
+        if (function_result) {
dc8c34
+            slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET_SIZE_ESTIMATE, &estimate);
dc8c34
+            slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_ENTRY, NULL);
dc8c34
+            delete_search_result_set(pb, &sr);
dc8c34
         }
dc8c34
     }
dc8c34
     if (vlv_request_control)
dc8c34
@@ -853,7 +849,7 @@ ldbm_back_search( Slapi_PBlock *pb )
dc8c34
 
dc8c34
         slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
dc8c34
         slapi_pblock_get( pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx );
dc8c34
-        pagedresults_set_unindexed( pb->pb_conn, pr_idx );
dc8c34
+        pagedresults_set_unindexed( pb->pb_conn, pb->pb_op, pr_idx );
dc8c34
     }
dc8c34
 
dc8c34
     sr->sr_candidates = candidates;
dc8c34
@@ -1341,13 +1337,24 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
dc8c34
     int                    estimate = 0; /* estimated search result count */
dc8c34
     back_txn               txn = {NULL};
dc8c34
     int                    pr_idx = -1;
dc8c34
+    Slapi_Connection       *conn;
dc8c34
+    Slapi_Operation        *op;
dc8c34
 
dc8c34
+    slapi_pblock_get( pb, SLAPI_SEARCH_TARGET_SDN, &basesdn );
dc8c34
+    if (NULL == basesdn) {
dc8c34
+        slapi_send_ldap_result( pb, LDAP_INVALID_DN_SYNTAX, NULL,
dc8c34
+                               "Null target DN", 0, NULL );
dc8c34
+        return( -1 );
dc8c34
+    }
dc8c34
+    slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &sr );
dc8c34
+    if (NULL == sr) {
dc8c34
+        goto bail;
dc8c34
+    }
dc8c34
     slapi_pblock_get( pb, SLAPI_BACKEND, &be );
dc8c34
     slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
dc8c34
     slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
dc8c34
     slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
dc8c34
     slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
dc8c34
-    slapi_pblock_get( pb, SLAPI_SEARCH_TARGET_SDN, &basesdn );
dc8c34
     slapi_pblock_get( pb, SLAPI_NENTRIES, &nentries );
dc8c34
     slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &slimit );
dc8c34
     slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &tlimit );
dc8c34
@@ -1355,32 +1362,30 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
dc8c34
     slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
dc8c34
     slapi_pblock_get( pb, SLAPI_SEARCH_REFERRALS, &urls );
dc8c34
     slapi_pblock_get( pb, SLAPI_TARGET_UNIQUEID, &target_uniqueid );
dc8c34
-    slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &sr );
dc8c34
     slapi_pblock_get( pb, SLAPI_TXN, &txn.back_txn_txn );
dc8c34
-    slapi_pblock_get( pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx );
dc8c34
+    slapi_pblock_get( pb, SLAPI_CONNECTION, &conn );
dc8c34
+    slapi_pblock_get( pb, SLAPI_OPERATION, &op );
dc8c34
 
dc8c34
     if ( !txn.back_txn_txn ) {
dc8c34
         dblayer_txn_init( li, &txn );
dc8c34
         slapi_pblock_set( pb, SLAPI_TXN, txn.back_txn_txn );
dc8c34
     }
dc8c34
 
dc8c34
-    if (NULL == sr) {
dc8c34
-        goto bail;
dc8c34
-    }
dc8c34
-
dc8c34
     if (sr->sr_norm_filter) {
dc8c34
         int val = 1;
dc8c34
         slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_NORMALIZED, &val );
dc8c34
         filter = sr->sr_norm_filter;
dc8c34
     }
dc8c34
 
dc8c34
-    if (NULL == basesdn) {
dc8c34
-        slapi_send_ldap_result( pb, LDAP_INVALID_DN_SYNTAX, NULL,
dc8c34
-                               "Null target DN", 0, NULL );
dc8c34
-        return( -1 );
dc8c34
-    }
dc8c34
-
dc8c34
-    if (sr->sr_current_sizelimit >= 0) {
dc8c34
+    if (op_is_pagedresults(op)) {
dc8c34
+        int myslimit;
dc8c34
+        /* On Simple Paged Results search, sizelimit is appied for each page. */
dc8c34
+        slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx);
dc8c34
+        myslimit = pagedresults_get_sizelimit(conn, op, pr_idx);
dc8c34
+        if (myslimit >= 0) {
dc8c34
+            slimit = myslimit;
dc8c34
+        }
dc8c34
+    } else if (sr->sr_current_sizelimit >= 0) {
dc8c34
         /* 
dc8c34
          * sr_current_sizelimit contains the current sizelimit.
dc8c34
          * In case of paged results, getting one page is one operation,
dc8c34
@@ -1397,8 +1402,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
dc8c34
     /* Return to the cache the entry we handed out last time */
dc8c34
     /* If we are using the extension, the front end will tell
dc8c34
      * us when to do this so we don't do it now */
dc8c34
-    if ( !use_extension )
dc8c34
-    {
dc8c34
+    if (sr->sr_entry && !use_extension) {
dc8c34
         CACHE_RETURN( &inst->inst_cache, &(sr->sr_entry) );
dc8c34
         sr->sr_entry = NULL;
dc8c34
     }
dc8c34
@@ -1422,15 +1426,12 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
dc8c34
         /* check for abandon */
dc8c34
         if ( slapi_op_abandoned( pb ) || (NULL == sr) )
dc8c34
         {
dc8c34
-            /* in case paged results, clean up the conn */
dc8c34
-            pagedresults_set_search_result( pb->pb_conn, NULL, 0, pr_idx );
dc8c34
-            slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
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( &sr );
dc8c34
+            delete_search_result_set(pb, &sr);
dc8c34
             rc = SLAPI_FAIL_GENERAL;
dc8c34
             goto bail;
dc8c34
         }
dc8c34
@@ -1439,15 +1440,12 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
dc8c34
         curtime = current_time();
dc8c34
         if ( tlimit != -1 && curtime > stoptime )
dc8c34
         {
dc8c34
-            /* in case paged results, clean up the conn */
dc8c34
-            pagedresults_set_search_result( pb->pb_conn, NULL, 0, pr_idx );
dc8c34
-            slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
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( &sr );
dc8c34
+            delete_search_result_set(pb, &sr);
dc8c34
             rc = SLAPI_FAIL_GENERAL;
dc8c34
             slapi_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL, NULL, nentries, urls );
dc8c34
             goto bail;
dc8c34
@@ -1456,15 +1454,12 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
dc8c34
         /* check lookthrough limit */
dc8c34
         if ( llimit != -1 && sr->sr_lookthroughcount >= llimit )
dc8c34
         {
dc8c34
-            /* in case paged results, clean up the conn */
dc8c34
-            pagedresults_set_search_result( pb->pb_conn, NULL, 0, pr_idx );
dc8c34
-            slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
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( &sr );
dc8c34
+            delete_search_result_set(pb, &sr);
dc8c34
             rc = SLAPI_FAIL_GENERAL;
dc8c34
             slapi_send_ldap_result( pb, LDAP_ADMINLIMIT_EXCEEDED, NULL, NULL, nentries, urls );
dc8c34
             goto bail;
dc8c34
@@ -1476,15 +1471,12 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
dc8c34
         {
dc8c34
             /* No more entries */
dc8c34
             /* destroy back_search_result_set */
dc8c34
-            /* in case paged results, clean up the conn */
dc8c34
-            pagedresults_set_search_result( pb->pb_conn, NULL, 0, pr_idx );
dc8c34
-            slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
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( &sr );
dc8c34
+            delete_search_result_set(pb, &sr);
dc8c34
             rc = 0;
dc8c34
             goto bail;
dc8c34
         }
dc8c34
@@ -1617,17 +1609,20 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
dc8c34
                  {
dc8c34
                      if ( --slimit < 0 ) {
dc8c34
                          CACHE_RETURN( &inst->inst_cache, &e );
dc8c34
-                         /* in case paged results, clean up the conn */
dc8c34
-                         pagedresults_set_search_result( pb->pb_conn, NULL,
dc8c34
-                                                         0, pr_idx);
dc8c34
-                         slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
dc8c34
                          slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET_SIZE_ESTIMATE, &estimate );
dc8c34
-                         delete_search_result_set( &sr );
dc8c34
+                         delete_search_result_set(pb, &sr);
dc8c34
                          slapi_send_ldap_result( pb, LDAP_SIZELIMIT_EXCEEDED, NULL, NULL, nentries, urls );
dc8c34
                          rc = SLAPI_FAIL_GENERAL;
dc8c34
                          goto bail;
dc8c34
                      }
dc8c34
                      slapi_pblock_set( pb, SLAPI_SEARCH_SIZELIMIT, &slimit );
dc8c34
+                     if (op_is_pagedresults(op)) {
dc8c34
+                         /* 
dc8c34
+                          * On Simple Paged Results search,
dc8c34
+                          * sizelimit is appied to each page.
dc8c34
+                          */
dc8c34
+                         pagedresults_set_sizelimit(conn, op, slimit, pr_idx);
dc8c34
+                     }
dc8c34
                      sr->sr_current_sizelimit = slimit;
dc8c34
                  }
dc8c34
                  if ( (filter_test != 0) && sr->sr_virtuallistview)
dc8c34
@@ -1734,13 +1729,20 @@ new_search_result_set(IDList *idl, int vlv, int lookthroughlimit)
dc8c34
 }
dc8c34
 
dc8c34
 static void
dc8c34
-delete_search_result_set( back_search_result_set **sr )
dc8c34
+delete_search_result_set( Slapi_PBlock *pb, back_search_result_set **sr )
dc8c34
 {
dc8c34
     int rc = 0, filt_errs = 0;
dc8c34
-    if ( NULL == sr || NULL == *sr)
dc8c34
+    if ( NULL == sr || NULL == *sr )
dc8c34
     {
dc8c34
         return;
dc8c34
     }
dc8c34
+    if (pb) {
dc8c34
+        if (op_is_pagedresults(pb->pb_op)) {
dc8c34
+            /* If the op is pagedresults, let the module clean up sr. */
dc8c34
+            return;
dc8c34
+        }
dc8c34
+        slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET, NULL);
dc8c34
+    }
dc8c34
     if ( NULL != (*sr)->sr_candidates )
dc8c34
     {
dc8c34
         idl_free( (*sr)->sr_candidates );
dc8c34
@@ -1755,12 +1757,17 @@ delete_search_result_set( back_search_result_set **sr )
dc8c34
     slapi_filter_free((*sr)->sr_norm_filter, 1);
dc8c34
     memset( *sr, 0, sizeof( back_search_result_set ) );
dc8c34
     slapi_ch_free( (void**)sr );
dc8c34
+    return;
dc8c34
 }
dc8c34
 
dc8c34
+/*
dc8c34
+ * This function is called from pagedresults free/cleanup functions.
dc8c34
+ */ 
dc8c34
 void
dc8c34
 ldbm_back_search_results_release( void **sr )
dc8c34
 {
dc8c34
-    delete_search_result_set( (back_search_result_set **)sr );
dc8c34
+    /* passing NULL pb forces to delete the search result set */
dc8c34
+    delete_search_result_set( NULL, (back_search_result_set **)sr );
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/vlv.c b/ldap/servers/slapd/back-ldbm/vlv.c
dc8c34
index 2c09531..dcc42fa 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/vlv.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/vlv.c
dc8c34
@@ -1156,7 +1156,7 @@ vlv_search_build_candidate_list(Slapi_PBlock *pb, const Slapi_DN *base, int *vlv
dc8c34
 	    slapi_pblock_get( pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx );
dc8c34
 	    slapi_rwlock_unlock(be->vlvSearchList_lock);
dc8c34
 	    slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
dc8c34
-	    pagedresults_set_unindexed( pb->pb_conn, pr_idx );
dc8c34
+	    pagedresults_set_unindexed( pb->pb_conn, pb->pb_op, pr_idx );
dc8c34
 	    rc = VLV_FIND_SEARCH_FAILED;
dc8c34
 	} else if((*vlv_rc=vlvIndex_accessallowed(pi, pb)) != LDAP_SUCCESS) {
dc8c34
 	    slapi_rwlock_unlock(be->vlvSearchList_lock);
dc8c34
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
dc8c34
index 0a87293..75a83c0 100644
dc8c34
--- a/ldap/servers/slapd/daemon.c
dc8c34
+++ b/ldap/servers/slapd/daemon.c
dc8c34
@@ -1363,14 +1363,19 @@ void slapd_daemon( daemon_ports_t *ports )
dc8c34
 		mapping_tree_free ();
dc8c34
 	}
dc8c34
 
dc8c34
+	/* 
dc8c34
+	 * connection_table_free could use callbacks in the backend.
dc8c34
+	 * (e.g., be_search_results_release)
dc8c34
+	 * Thus, it needs to be called before be_cleanupall.
dc8c34
+	 */
dc8c34
+	connection_table_free(the_connection_table);
dc8c34
+	the_connection_table= NULL;
dc8c34
+
dc8c34
 	be_cleanupall (); 
dc8c34
-    LDAPDebug( LDAP_DEBUG_TRACE, "slapd shutting down - backends closed down\n",
dc8c34
+	LDAPDebug( LDAP_DEBUG_TRACE, "slapd shutting down - backends closed down\n",
dc8c34
 			0, 0, 0 );
dc8c34
 	referrals_free();
dc8c34
 
dc8c34
-	connection_table_free(the_connection_table);
dc8c34
-	the_connection_table= NULL;
dc8c34
-
dc8c34
 	/* tell the time thread to shutdown and then wait for it */
dc8c34
 	time_shutdown = 1;
dc8c34
 	PR_JoinThread( time_thread_p );
dc8c34
diff --git a/ldap/servers/slapd/operation.c b/ldap/servers/slapd/operation.c
dc8c34
index 13e05c1..01ebfef 100644
dc8c34
--- a/ldap/servers/slapd/operation.c
dc8c34
+++ b/ldap/servers/slapd/operation.c
dc8c34
@@ -201,10 +201,11 @@ operation_new(int flags)
dc8c34
 		o->o_next = NULL;
dc8c34
 		o->o_flags= flags;
dc8c34
 		if ( config_get_accesslog_level() & LDAP_DEBUG_TIMING ) {
dc8c34
-                    o->o_interval = PR_IntervalNow();
dc8c34
-                } else {
dc8c34
-                    o->o_interval = (PRIntervalTime)0;
dc8c34
-                }
dc8c34
+			o->o_interval = PR_IntervalNow();
dc8c34
+		} else {
dc8c34
+			o->o_interval = (PRIntervalTime)0;
dc8c34
+		}
dc8c34
+		o->o_pagedresults_sizelimit = -1;
dc8c34
 	}
dc8c34
 	return o;
dc8c34
 }
dc8c34
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
dc8c34
index fabe8a4..a96b950 100644
dc8c34
--- a/ldap/servers/slapd/opshared.c
dc8c34
+++ b/ldap/servers/slapd/opshared.c
dc8c34
@@ -245,7 +245,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
   int             internal_op;
dc8c34
   Slapi_DN        *basesdn = NULL;
dc8c34
   Slapi_DN        *sdn = NULL;
dc8c34
-  Slapi_Operation *operation;
dc8c34
+  Slapi_Operation *operation = NULL;
dc8c34
   Slapi_Entry     *referral = NULL;
dc8c34
   char            *proxydn = NULL; 
dc8c34
   char            *proxystr = NULL;
dc8c34
@@ -271,7 +271,6 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
   int curr_search_count = 0;
dc8c34
   Slapi_Backend *pr_be = NULL;
dc8c34
   void *pr_search_result = NULL;
dc8c34
-  int pr_reset_processing = 0;
dc8c34
   int pr_idx = -1;
dc8c34
   Slapi_DN *orig_sdn = NULL;
dc8c34
   int free_sdn = 0;
dc8c34
@@ -469,23 +468,16 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
           if ((LDAP_SUCCESS == rc) ||
dc8c34
               (LDAP_CANCELLED == rc) || (0 == pagesize)) {
dc8c34
               unsigned int opnote = SLAPI_OP_NOTE_SIMPLEPAGED;
dc8c34
-              if (pagedresults_check_or_set_processing(pb->pb_conn, pr_idx)) {
dc8c34
-                  send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM,
dc8c34
-                                   NULL, "Simple Paged Results Search "
dc8c34
-                                   "already in progress on this connection",
dc8c34
-                                   0, NULL);
dc8c34
-                  goto free_and_return_nolock;
dc8c34
-              }
dc8c34
-              /* need to reset after we are done with this op */
dc8c34
-              pr_reset_processing = 1;
dc8c34
               op_set_pagedresults(operation);
dc8c34
               pr_be = pagedresults_get_current_be(pb->pb_conn, pr_idx);
dc8c34
               pr_search_result = pagedresults_get_search_result(pb->pb_conn,
dc8c34
+                                                                operation,
dc8c34
                                                                 pr_idx);
dc8c34
               estimate = 
dc8c34
                  pagedresults_get_search_result_set_size_estimate(pb->pb_conn,
dc8c34
+                                                                  operation,
dc8c34
                                                                   pr_idx);
dc8c34
-              if (pagedresults_get_unindexed(pb->pb_conn, pr_idx)) {
dc8c34
+              if (pagedresults_get_unindexed(pb->pb_conn, operation, pr_idx)) {
dc8c34
                   opnote |= SLAPI_OP_NOTE_UNINDEXED;
dc8c34
               }
dc8c34
               slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
dc8c34
@@ -640,7 +632,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
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, time_up, pr_idx);
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
@@ -694,12 +686,25 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
     if (op_is_pagedresults(operation) && pr_search_result) {
dc8c34
       void *sr = NULL;
dc8c34
       /* PAGED RESULTS and already have the search results from the prev op */
dc8c34
-      slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, pr_search_result );
dc8c34
-      rc = send_results_ext (pb, 1, &pnentries, pagesize, &pr_stat);
dc8c34
+      pagedresults_lock(pb->pb_conn, pr_idx);
dc8c34
+      /* 
dc8c34
+       * In async paged result case, the search result might be released
dc8c34
+       * by other theads.  We need to double check it in the locked region.
dc8c34
+       */
dc8c34
+      pr_search_result = pagedresults_get_search_result(pb->pb_conn, 
dc8c34
+                                                        operation,
dc8c34
+                                                        pr_idx);
dc8c34
+      if (pr_search_result) {
dc8c34
+        slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, pr_search_result );
dc8c34
+        rc = send_results_ext (pb, 1, &pnentries, pagesize, &pr_stat);
dc8c34
 
dc8c34
-      /* search result could be reset in the backend/dse */
dc8c34
-      slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET, &sr);
dc8c34
-      pagedresults_set_search_result(pb->pb_conn, sr, 0, pr_idx);
dc8c34
+        /* search result could be reset in the backend/dse */
dc8c34
+        slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET, &sr);
dc8c34
+        pagedresults_set_search_result(pb->pb_conn, operation, sr, 0, pr_idx);
dc8c34
+      } else {
dc8c34
+        pr_stat = PAGEDRESULTS_SEARCH_END;
dc8c34
+      }
dc8c34
+      pagedresults_unlock(pb->pb_conn, pr_idx);
dc8c34
 
dc8c34
       if (PAGEDRESULTS_SEARCH_END == pr_stat) {
dc8c34
         /* no more entries to send in the backend */
dc8c34
@@ -720,14 +725,18 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
       }
dc8c34
       pagedresults_set_response_control(pb, 0, estimate,
dc8c34
                                         curr_search_count, pr_idx);
dc8c34
-      if (pagedresults_get_with_sort(pb->pb_conn, pr_idx)) {
dc8c34
+      if (pagedresults_get_with_sort(pb->pb_conn, operation, pr_idx)) {
dc8c34
         sort_make_sort_response_control(pb, CONN_GET_SORT_RESULT_CODE, NULL);
dc8c34
       }
dc8c34
       pagedresults_set_search_result_set_size_estimate(pb->pb_conn, 
dc8c34
+                                                       operation,
dc8c34
                                                        estimate, pr_idx);
dc8c34
       next_be = NULL; /* to break the loop */
dc8c34
       if (curr_search_count == -1) {
dc8c34
-        pagedresults_free_one(pb->pb_conn, pr_idx);
dc8c34
+        pagedresults_lock(pb->pb_conn, pr_idx);
dc8c34
+        slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET, NULL);
dc8c34
+        pagedresults_free_one(pb->pb_conn, operation, pr_idx);
dc8c34
+        pagedresults_unlock(pb->pb_conn, pr_idx);
dc8c34
       }
dc8c34
     } else {
dc8c34
       /* be_suffix null means that we are searching the default backend
dc8c34
@@ -849,7 +858,11 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
             int with_sort = operation->o_flags & OP_FLAG_SERVER_SIDE_SORTING;
dc8c34
   
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
+                be->be_search_results_release(&sr);
dc8c34
+              }
dc8c34
               if (NULL == next_be) {
dc8c34
                 /* no more entries && no more backends */
dc8c34
                 curr_search_count = -1;
dc8c34
@@ -861,24 +874,31 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
dc8c34
               }
dc8c34
             } else {
dc8c34
               curr_search_count = pnentries;
dc8c34
-              slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET, &sr);
dc8c34
               slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET_SIZE_ESTIMATE, &estimate);
dc8c34
-              if (pagedresults_set_current_be(pb->pb_conn, be, pr_idx) < 0 ||
dc8c34
-                  pagedresults_set_search_result(pb->pb_conn, sr, 0, pr_idx) < 0 ||
dc8c34
-                  pagedresults_set_search_result_count(pb->pb_conn,
dc8c34
-                                                   curr_search_count, pr_idx) < 0 ||
dc8c34
-                  pagedresults_set_search_result_set_size_estimate(pb->pb_conn,
dc8c34
-                                                   estimate, pr_idx) < 0 ||
dc8c34
-                  pagedresults_set_with_sort(pb->pb_conn, with_sort, pr_idx) < 0) {
dc8c34
+              pagedresults_lock(pb->pb_conn, pr_idx);
dc8c34
+              if ((pagedresults_set_current_be(pb->pb_conn, be, pr_idx) < 0) ||
dc8c34
+                  (pagedresults_set_search_result(pb->pb_conn, operation,
dc8c34
+                                                  sr, 0, pr_idx) < 0) ||
dc8c34
+                  (pagedresults_set_search_result_count(pb->pb_conn, operation,
dc8c34
+                                                        curr_search_count,
dc8c34
+                                                        pr_idx) < 0) ||
dc8c34
+                  (pagedresults_set_search_result_set_size_estimate(pb->pb_conn,
dc8c34
+                                                                 operation,
dc8c34
+                                                                 estimate,
dc8c34
+                                                                 pr_idx) < 0) ||
dc8c34
+                  (pagedresults_set_with_sort(pb->pb_conn, operation,
dc8c34
+                                              with_sort, pr_idx) < 0)) {
dc8c34
+                pagedresults_unlock(pb->pb_conn, pr_idx);
dc8c34
                 goto free_and_return;
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 (curr_search_count == -1) {
dc8c34
-                pagedresults_free_one(pb->pb_conn, pr_idx);
dc8c34
+                pagedresults_free_one(pb->pb_conn, operation, pr_idx);
dc8c34
             }
dc8c34
         }
dc8c34
   
dc8c34
@@ -1007,9 +1027,6 @@ free_and_return_nolock:
dc8c34
 
dc8c34
   slapi_ch_free_string(&proxydn);
dc8c34
   slapi_ch_free_string(&proxystr);
dc8c34
-  if (pr_reset_processing) {
dc8c34
-    pagedresults_reset_processing(pb->pb_conn, pr_idx);
dc8c34
-  }
dc8c34
 }
dc8c34
 
dc8c34
 /* Returns 1 if this processing on this entry is finished
dc8c34
@@ -1257,7 +1274,7 @@ iterate(Slapi_PBlock *pb, Slapi_Backend *be, int send_result,
dc8c34
 
dc8c34
     *pnentries = 0;
dc8c34
     
dc8c34
-    while (!done) 
dc8c34
+    while (!done)
dc8c34
     {
dc8c34
         Slapi_Entry *gerentry = NULL;
dc8c34
         Slapi_Operation *operation;
dc8c34
@@ -1275,7 +1292,7 @@ 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, 0, pr_idx);
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 9b294eb..78bd6b0 100644
dc8c34
--- a/ldap/servers/slapd/pagedresults.c
dc8c34
+++ b/ldap/servers/slapd/pagedresults.c
dc8c34
@@ -131,6 +131,7 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
             }
dc8c34
         }
dc8c34
         conn->c_pagedresults.prl_count++;
dc8c34
+        conn->c_pagedresults.prl_list[*index].pr_mutex = PR_NewLock();
dc8c34
     } else {
dc8c34
         /* Repeated paged results request.
dc8c34
          * PagedResults is already allocated. */
dc8c34
@@ -140,6 +141,8 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
         *index = strtol(ptr, NULL, 10);
dc8c34
         slapi_ch_free_string(&ptr);
dc8c34
     }
dc8c34
+    /* reset sizelimit */
dc8c34
+    op->o_pagedresults_sizelimit = -1;
dc8c34
     slapi_ch_free((void **)&cookie.bv_val);
dc8c34
 
dc8c34
     if ((*index > -1) && (*index < conn->c_pagedresults.prl_maxlen)) {
dc8c34
@@ -243,10 +246,13 @@ bailout:
dc8c34
 }
dc8c34
 
dc8c34
 int 
dc8c34
-pagedresults_free_one( Connection *conn, int index )
dc8c34
+pagedresults_free_one( Connection *conn, Operation *op, int index )
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
 
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return 0; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_free_one: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
@@ -256,13 +262,19 @@ pagedresults_free_one( Connection *conn, 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
+            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
             conn->c_pagedresults.prl_count--;
dc8c34
             rc = 0;
dc8c34
         }
dc8c34
@@ -348,9 +360,12 @@ pagedresults_set_current_be(Connection *conn, Slapi_Backend *be, int index)
dc8c34
 }
dc8c34
 
dc8c34
 void *
dc8c34
-pagedresults_get_search_result(Connection *conn, int index)
dc8c34
+pagedresults_get_search_result(Connection *conn, Operation *op, int index)
dc8c34
 {
dc8c34
     void *sr = NULL;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return sr; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_get_search_result: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
@@ -366,20 +381,31 @@ pagedresults_get_search_result(Connection *conn, int index)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_set_search_result(Connection *conn, void *sr, 
dc8c34
+pagedresults_set_search_result(Connection *conn, Operation *op, void *sr, 
dc8c34
                                int locked, int index)
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return 0; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug2Args(LDAP_DEBUG_TRACE,
dc8c34
                    "--> pagedresults_set_search_result: idx=%d, sr=%p\n",
dc8c34
                    index, sr);
dc8c34
     if (conn && (index > -1)) {
dc8c34
         if (!locked) PR_Lock(conn->c_mutex);
dc8c34
         if (index < conn->c_pagedresults.prl_maxlen) {
dc8c34
-            conn->c_pagedresults.prl_list[index].pr_search_result_set = sr;
dc8c34
+            if (sr) { /* set */
dc8c34
+                if (NULL ==
dc8c34
+                    conn->c_pagedresults.prl_list[index].pr_search_result_set) {
dc8c34
+                    conn->c_pagedresults.prl_list[index].pr_search_result_set = sr;
dc8c34
+                    rc = 0;
dc8c34
+                }
dc8c34
+            } else {  /* reset */
dc8c34
+                conn->c_pagedresults.prl_list[index].pr_search_result_set = sr;
dc8c34
+                rc = 0;
dc8c34
+            }
dc8c34
         }
dc8c34
         if (!locked) PR_Unlock(conn->c_mutex);
dc8c34
-        rc = 0;
dc8c34
     }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "<-- pagedresults_set_search_result: %d\n", rc);
dc8c34
@@ -387,9 +413,12 @@ pagedresults_set_search_result(Connection *conn, void *sr,
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_get_search_result_count(Connection *conn, int index)
dc8c34
+pagedresults_get_search_result_count(Connection *conn, Operation *op, int index)
dc8c34
 {
dc8c34
     int count = 0;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return count; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_get_search_result_count: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
@@ -405,9 +434,13 @@ pagedresults_get_search_result_count(Connection *conn, int index)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_set_search_result_count(Connection *conn, int count, int index)
dc8c34
+pagedresults_set_search_result_count(Connection *conn, Operation *op,
dc8c34
+                                     int count, int index)
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return rc; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_set_search_result_count: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
@@ -424,9 +457,14 @@ pagedresults_set_search_result_count(Connection *conn, int count, int index)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_get_search_result_set_size_estimate(Connection *conn, int index)
dc8c34
+pagedresults_get_search_result_set_size_estimate(Connection *conn, 
dc8c34
+                                                 Operation *op,
dc8c34
+                                                 int index)
dc8c34
 {
dc8c34
     int count = 0;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return count; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_get_search_result_set_size_estimate: "
dc8c34
                   "idx=%d\n", index);
dc8c34
@@ -445,9 +483,13 @@ pagedresults_get_search_result_set_size_estimate(Connection *conn, int index)
dc8c34
 
dc8c34
 int
dc8c34
 pagedresults_set_search_result_set_size_estimate(Connection *conn, 
dc8c34
+                                                 Operation *op,
dc8c34
                                                  int count, int index)
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return rc; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_set_search_result_set_size_estimate: "
dc8c34
                   "idx=%d\n", index);
dc8c34
@@ -466,9 +508,12 @@ pagedresults_set_search_result_set_size_estimate(Connection *conn,
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_get_with_sort(Connection *conn, int index)
dc8c34
+pagedresults_get_with_sort(Connection *conn, Operation *op, int index)
dc8c34
 {
dc8c34
     int flags = 0;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return flags; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_get_with_sort: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
@@ -484,9 +529,13 @@ pagedresults_get_with_sort(Connection *conn, int index)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_set_with_sort(Connection *conn, int flags, int index)
dc8c34
+pagedresults_set_with_sort(Connection *conn, Operation *op,
dc8c34
+                           int flags, int index)
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return rc; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_set_with_sort: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
@@ -505,9 +554,12 @@ pagedresults_set_with_sort(Connection *conn, int flags, int index)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_get_unindexed(Connection *conn, int index)
dc8c34
+pagedresults_get_unindexed(Connection *conn, Operation *op, int index)
dc8c34
 {
dc8c34
     int flags = 0;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return flags; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_get_unindexed: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
@@ -523,9 +575,12 @@ pagedresults_get_unindexed(Connection *conn, int index)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_set_unindexed(Connection *conn, int index)
dc8c34
+pagedresults_set_unindexed(Connection *conn, Operation *op, int index)
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return rc; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_set_unindexed: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
@@ -543,9 +598,12 @@ pagedresults_set_unindexed(Connection *conn, int index)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_get_sort_result_code(Connection *conn, int index)
dc8c34
+pagedresults_get_sort_result_code(Connection *conn, Operation *op, int index)
dc8c34
 {
dc8c34
     int code = LDAP_OPERATIONS_ERROR;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return code; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_get_sort_result_code: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
@@ -561,9 +619,13 @@ pagedresults_get_sort_result_code(Connection *conn, int index)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_set_sort_result_code(Connection *conn, int code, int index)
dc8c34
+pagedresults_set_sort_result_code(Connection *conn, Operation *op,
dc8c34
+                                  int code, int index)
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return rc; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_set_sort_result_code: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
@@ -580,9 +642,13 @@ pagedresults_set_sort_result_code(Connection *conn, int code, int index)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-pagedresults_set_timelimit(Connection *conn, time_t timelimit, int index)
dc8c34
+pagedresults_set_timelimit(Connection *conn, Operation *op,
dc8c34
+                           time_t timelimit, int index)
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return rc; /* noop */
dc8c34
+    }
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_set_timelimit: idx=%d\n", index);
dc8c34
     if (conn && (index > -1)) {
dc8c34
@@ -597,6 +663,35 @@ pagedresults_set_timelimit(Connection *conn, time_t timelimit, int index)
dc8c34
     return rc;
dc8c34
 }
dc8c34
 
dc8c34
+int
dc8c34
+pagedresults_set_sizelimit(Connection *conn, Operation *op,
dc8c34
+                           int sizelimit, int index)
dc8c34
+{
dc8c34
+    int rc = -1;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return rc; /* noop */
dc8c34
+    }
dc8c34
+    LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
+                  "--> pagedresults_set_sizelimit: idx=%d\n", index);
dc8c34
+    op->o_pagedresults_sizelimit = sizelimit;
dc8c34
+    LDAPDebug1Arg(LDAP_DEBUG_TRACE, "<-- pagedresults_set_sizelimit: %d\n", rc);
dc8c34
+    return rc;
dc8c34
+}
dc8c34
+
dc8c34
+int
dc8c34
+pagedresults_get_sizelimit(Connection *conn, Operation *op, int index)
dc8c34
+{
dc8c34
+    int sizelimit = -1;
dc8c34
+    if (!op_is_pagedresults(op)) {
dc8c34
+        return sizelimit; /* noop */
dc8c34
+    }
dc8c34
+    LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
+                  "--> pagedresults_get_sizelimit: idx=%d\n", index);
dc8c34
+    sizelimit = op->o_pagedresults_sizelimit;
dc8c34
+    LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_get_sizelimit\n");
dc8c34
+    return sizelimit;
dc8c34
+}
dc8c34
+
dc8c34
 /*
dc8c34
  * pagedresults_cleanup cleans up the pagedresults list;
dc8c34
  * it does not free the list.
dc8c34
@@ -629,6 +724,9 @@ pagedresults_cleanup(Connection *conn, int needlock)
dc8c34
             prp->pr_current_be->be_search_results_release(&(prp->pr_search_result_set));
dc8c34
             rc = 1;
dc8c34
         }
dc8c34
+        if (prp->pr_mutex) {
dc8c34
+            PR_DestroyLock(prp->pr_mutex);
dc8c34
+        }
dc8c34
         memset(prp, '\0', sizeof(PagedResults));
dc8c34
     }
dc8c34
     conn->c_pagedresults.prl_count = 0;
dc8c34
@@ -665,6 +763,9 @@ pagedresults_cleanup_all(Connection *conn, int needlock)
dc8c34
     for (i = 0; conn->c_pagedresults.prl_list &&
dc8c34
                 i < conn->c_pagedresults.prl_maxlen; i++) {
dc8c34
         prp = conn->c_pagedresults.prl_list + i;
dc8c34
+        if (prp->pr_mutex) {
dc8c34
+            PR_DestroyLock(prp->pr_mutex);
dc8c34
+        }
dc8c34
         if (prp->pr_current_be && prp->pr_search_result_set &&
dc8c34
             prp->pr_current_be->be_search_results_release) {
dc8c34
             prp->pr_current_be->be_search_results_release(&(prp->pr_search_result_set));
dc8c34
@@ -681,6 +782,7 @@ pagedresults_cleanup_all(Connection *conn, int needlock)
dc8c34
     return rc;
dc8c34
 }
dc8c34
 
dc8c34
+#if 0 /* Stopped using it (#47347) */
dc8c34
 /*
dc8c34
  * check to see if this connection is currently processing
dc8c34
  * a pagedresults search - if it is, return True - if not,
dc8c34
@@ -734,6 +836,7 @@ pagedresults_reset_processing(Connection *conn, int index)
dc8c34
                   "<-- pagedresults_reset_processing: %d\n", ret);
dc8c34
     return ret;
dc8c34
 }
dc8c34
+#endif
dc8c34
 
dc8c34
 /* Are all the paged results requests timed out? */
dc8c34
 int
dc8c34
@@ -819,3 +922,35 @@ op_set_pagedresults(Operation *op)
dc8c34
     }
dc8c34
     op->o_flags |= OP_FLAG_PAGED_RESULTS;
dc8c34
 }
dc8c34
+
dc8c34
+/*
dc8c34
+ * pagedresults_lock/unlock -- introduced to protect search results for the
dc8c34
+ * asynchronous searches.
dc8c34
+ */
dc8c34
+void
dc8c34
+pagedresults_lock( Connection *conn, int index )
dc8c34
+{
dc8c34
+    PagedResults *prp;
dc8c34
+    if (!conn || (index < 0) || (index >= conn->c_pagedresults.prl_maxlen)) {
dc8c34
+        return;
dc8c34
+    }
dc8c34
+    prp = conn->c_pagedresults.prl_list + index;
dc8c34
+    if (prp->pr_mutex) {
dc8c34
+        PR_Lock(prp->pr_mutex);
dc8c34
+    }
dc8c34
+    return;
dc8c34
+}
dc8c34
+
dc8c34
+void
dc8c34
+pagedresults_unlock( Connection *conn, int index )
dc8c34
+{
dc8c34
+    PagedResults *prp;
dc8c34
+    if (!conn || (index < 0) || (index >= conn->c_pagedresults.prl_maxlen)) {
dc8c34
+        return;
dc8c34
+    }
dc8c34
+    prp = conn->c_pagedresults.prl_list + index;
dc8c34
+    if (prp->pr_mutex) {
dc8c34
+        PR_Unlock(prp->pr_mutex);
dc8c34
+    }
dc8c34
+    return;
dc8c34
+}
dc8c34
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
dc8c34
index a68c2d9..911dadd 100644
dc8c34
--- a/ldap/servers/slapd/proto-slap.h
dc8c34
+++ b/ldap/servers/slapd/proto-slap.h
dc8c34
@@ -1405,34 +1405,48 @@ void pagedresults_set_response_control(Slapi_PBlock *pb, int iscritical,
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
-void *pagedresults_get_search_result(Connection *conn, int index);
dc8c34
-int pagedresults_set_search_result(Connection *conn, void *sr, 
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
                                    int locked, int index);
dc8c34
-int pagedresults_get_search_result_count(Connection *conn, int index);
dc8c34
-int pagedresults_set_search_result_count(Connection *conn, int cnt, int index);
dc8c34
-int pagedresults_get_search_result_set_size_estimate(Connection *conn, 
dc8c34
+int pagedresults_get_search_result_count(Connection *conn, Operation *op,
dc8c34
+                                         int index);
dc8c34
+int pagedresults_set_search_result_count(Connection *conn, Operation *op,                                                int cnt, int index);
dc8c34
+int pagedresults_get_search_result_set_size_estimate(Connection *conn,
dc8c34
+                                                     Operation *op, 
dc8c34
                                                      int index);
dc8c34
-int pagedresults_set_search_result_set_size_estimate(Connection *conn, int cnt, 
dc8c34
+int pagedresults_set_search_result_set_size_estimate(Connection *conn,
dc8c34
+                                                     Operation *op, int cnt, 
dc8c34
                                                      int index);
dc8c34
-int pagedresults_get_with_sort(Connection *conn, int index);
dc8c34
-int pagedresults_set_with_sort(Connection *conn, int flags, int index);
dc8c34
-int pagedresults_get_unindexed(Connection *conn, int index);
dc8c34
-int pagedresults_set_unindexed(Connection *conn, int index);
dc8c34
-int pagedresults_get_sort_result_code(Connection *conn, int index);
dc8c34
-int pagedresults_set_sort_result_code(Connection *conn, int code, int index);
dc8c34
-int pagedresults_set_timelimit(Connection *conn, time_t timelimit, int index);
dc8c34
+int pagedresults_get_with_sort(Connection *conn, Operation *op, int index);
dc8c34
+int pagedresults_set_with_sort(Connection *conn, Operation *op,
dc8c34
+                               int flags, int index);
dc8c34
+int pagedresults_get_unindexed(Connection *conn, Operation *op, int index);
dc8c34
+int pagedresults_set_unindexed(Connection *conn, Operation *op, int index);
dc8c34
+int pagedresults_get_sort_result_code(Connection *conn, Operation *op,
dc8c34
+                                      int index);
dc8c34
+int pagedresults_set_sort_result_code(Connection *conn, Operation *op,
dc8c34
+                                      int code, int index);
dc8c34
+int pagedresults_set_timelimit(Connection *conn, Operation *op,
dc8c34
+                               time_t timelimit, int index);
dc8c34
+int pagedresults_get_sizelimit(Connection *conn, Operation *op, int index);
dc8c34
+int pagedresults_set_sizelimit(Connection *conn, Operation *op,
dc8c34
+                               int sizelimit, int index);
dc8c34
 int pagedresults_cleanup(Connection *conn, int needlock);
dc8c34
+#if 0 /* Stopped using it (#47347) */
dc8c34
 int pagedresults_check_or_set_processing(Connection *conn, int index);
dc8c34
 int pagedresults_reset_processing(Connection *conn, int index);
dc8c34
+#endif
dc8c34
 int pagedresults_is_timedout_nolock(Connection *conn);
dc8c34
 int pagedresults_reset_timedout_nolock(Connection *conn);
dc8c34
 int pagedresults_in_use_nolock(Connection *conn);
dc8c34
-int pagedresults_free_one(Connection *conn, int index);
dc8c34
-int pagedresults_free_one_msgid_nolock( Connection *conn, ber_int_t msgid );
dc8c34
+int pagedresults_free_one(Connection *conn, Operation *op, int index);
dc8c34
+int pagedresults_free_one_msgid_nolock(Connection *conn, ber_int_t msgid);
dc8c34
 int op_is_pagedresults(Operation *op);
dc8c34
 int pagedresults_cleanup_all(Connection *conn, int needlock);
dc8c34
 void op_set_pagedresults(Operation *op);
dc8c34
-
dc8c34
+void pagedresults_lock(Connection *conn, int index);
dc8c34
+void pagedresults_unlock(Connection *conn, int index);
dc8c34
 
dc8c34
 /*
dc8c34
  * sort.c
dc8c34
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
dc8c34
index d290c92..ef986e2 100644
dc8c34
--- a/ldap/servers/slapd/slap.h
dc8c34
+++ b/ldap/servers/slapd/slap.h
dc8c34
@@ -1339,6 +1339,7 @@ typedef struct op {
dc8c34
 	unsigned long o_abandoned_op; /* operation abandoned by this operation - used to decide which plugins to invoke */
dc8c34
 	struct slapi_operation_parameters o_params;
dc8c34
 	struct slapi_operation_results o_results;
dc8c34
+	int o_pagedresults_sizelimit;
dc8c34
 } Operation;
dc8c34
 
dc8c34
 /*
dc8c34
@@ -1367,6 +1368,7 @@ typedef struct _paged_results {
dc8c34
     time_t        pr_timelimit;           /* time limit for this request */
dc8c34
     int           pr_flags;
dc8c34
     ber_int_t     pr_msgid;               /* msgid of the request; to abandon */
dc8c34
+    PRLock        *pr_mutex;              /* protect each conn structure    */
dc8c34
 } PagedResults;
dc8c34
 
dc8c34
 /* array of simple paged structure stashed in connection */
dc8c34
diff --git a/ldap/servers/slapd/sort.c b/ldap/servers/slapd/sort.c
dc8c34
index 903fa6f..72c9ec9 100644
dc8c34
--- a/ldap/servers/slapd/sort.c
dc8c34
+++ b/ldap/servers/slapd/sort.c
dc8c34
@@ -58,12 +58,14 @@ sort_make_sort_response_control ( Slapi_PBlock *pb, int code, char *error_type)
dc8c34
     slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx);
dc8c34
 
dc8c34
     if (code == CONN_GET_SORT_RESULT_CODE) {
dc8c34
-        code = pagedresults_get_sort_result_code(pb->pb_conn, pr_idx);
dc8c34
+        code = pagedresults_get_sort_result_code(pb->pb_conn,
dc8c34
+                                                 pb->pb_op, pr_idx);
dc8c34
     } else {
dc8c34
         Slapi_Operation *operation;
dc8c34
         slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
dc8c34
         if (op_is_pagedresults(operation)) {
dc8c34
-            pagedresults_set_sort_result_code(pb->pb_conn, code, pr_idx);
dc8c34
+            pagedresults_set_sort_result_code(pb->pb_conn,
dc8c34
+                                              pb->pb_op, code, pr_idx);
dc8c34
         }
dc8c34
     }
dc8c34
 
dc8c34
-- 
dc8c34
1.8.1.4
dc8c34