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