From add880accaa28de8304da1c2c2f58fe8af002ebb Mon Sep 17 00:00:00 2001 From: Noriko Hosoi Date: Feb 29 2012 19:41:57 +0000 Subject: Trac Ticket #260 - 389 DS does not support multiple paging controls on a single connection https://fedorahosted.org/389/ticket/260 Fix description: 1. "Connection" object holds the paged results related values. Now they are packaged in one PagedResults object. And the array of PagedResults with its length and used count are placed in PagedResultList, which is stashed in Connection (slap.h). 2. The pagedresults APIs are extended to take the index of Paged- Results array. The index is set to the cookie in the Paged- Results control before returning it to the client. When a client sends a paged results request, the cookie field in the first request control is supposed to be empty. The result control is returned with the search results. The result control stores the index in the cookie and the client sets it to the following request control to get the next pages. When the paged search is done, empty cookie is returned. If a passed cookie is less than 0 or greater than the array size and the request control is "critical", the request fails with LDAP_PROTOCOL_ERROR and the error is logged in the error log. If the control is not "critical", the paged results request is disabled. 3. The array grows if multiple simple paged results requests over a single connection come in. The array does not get released every time, but it is when the server is shutdown. 4. Simple paged results connection is timed out when it exeeds the timelimit. If multiple requests are served, it won't be disconnected until all the requests are timed out. --- diff --git a/ldap/servers/slapd/abandon.c b/ldap/servers/slapd/abandon.c index 8870364..4f00da9 100644 --- a/ldap/servers/slapd/abandon.c +++ b/ldap/servers/slapd/abandon.c @@ -152,11 +152,12 @@ do_abandon( Slapi_PBlock *pb ) 0 ); } - if (pagedresults_cleanup(pb->pb_conn, 0 /* already locked */)) { - /* Cleaned up paged result connection */ - slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d ABANDON" - " targetop=Simple Paged Results\n", - pb->pb_conn->c_connid, pb->pb_op->o_opid ); + if ( op_is_pagedresults(o) ) { + if ( 0 == pagedresults_free_one_msgid(pb->pb_conn, id) ) { + slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 + " op=%d ABANDON targetop=Simple Paged Results\n", + pb->pb_conn->c_connid, pb->pb_op->o_opid ); + } } else if ( NULL == o ) { slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d ABANDON" " targetop=NOTFOUND msgid=%d\n", diff --git a/ldap/servers/slapd/back-ldbm/filterindex.c b/ldap/servers/slapd/back-ldbm/filterindex.c index fbc8ccf..27b20ec 100644 --- a/ldap/servers/slapd/back-ldbm/filterindex.c +++ b/ldap/servers/slapd/back-ldbm/filterindex.c @@ -223,6 +223,7 @@ ava_candidates( int unindexed = 0; Slapi_Attr sattr; back_txn txn = {NULL}; + int pr_idx = -1; LDAPDebug( LDAP_DEBUG_TRACE, "=> ava_candidates\n", 0, 0, 0 ); @@ -232,6 +233,7 @@ ava_candidates( return( NULL ); } + slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx); slapi_attr_init(&sattr, type); #ifdef LDAP_DEBUG @@ -315,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 ); + pagedresults_set_unindexed( pb->pb_conn, pr_idx ); } /* We don't use valuearray_free here since the valueset, berval @@ -347,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 ); + pagedresults_set_unindexed( pb->pb_conn, pr_idx ); } valuearray_free( &ivals ); LDAPDebug( LDAP_DEBUG_TRACE, "<= ava_candidates %lu\n", @@ -384,9 +386,11 @@ presence_candidates( NULL, &txn, err, &unindexed, allidslimit ); if ( unindexed ) { + int pr_idx = -1; unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED; slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote ); - pagedresults_set_unindexed( pb->pb_conn ); + slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx); + pagedresults_set_unindexed( pb->pb_conn, pr_idx ); } if (idl != NULL && ALLIDS(idl) && strcasecmp(type, "nscpentrydn") == 0) { @@ -492,10 +496,15 @@ extensible_candidates( index_range_read_ext(pb, be, mrTYPE, mrOID, mrOP, *key, NULL, 0, &txn, err, allidslimit); if ( unindexed ) { + int pr_idx = -1; unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED; slapi_pblock_set( glob_pb, - SLAPI_OPERATION_NOTES, &opnote ); - pagedresults_set_unindexed( glob_pb->pb_conn ); + SLAPI_OPERATION_NOTES, &opnote ); + slapi_pblock_get( glob_pb, + SLAPI_PAGED_RESULTS_INDEX, + &pr_idx ); + pagedresults_set_unindexed( glob_pb->pb_conn, + pr_idx ); } if (idl2 == NULL) { @@ -839,7 +848,7 @@ list_candidates( */ /* PAGED RESULTS: we strictly limit the idlist size by the allids (aka idlistscan) limit. */ - if (operation->o_flags & OP_FLAG_PAGED_RESULTS) { + if (op_is_pagedresults(operation)) { int nids = IDL_NIDS(idl); if ( allidslimit > 0 && nids > allidslimit ) { idl_free( idl ); @@ -887,6 +896,7 @@ substring_candidates( unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED; Slapi_Attr sattr; back_txn txn = {NULL}; + int pr_idx = -1; LDAPDebug( LDAP_DEBUG_TRACE, "=> sub_candidates\n", 0, 0, 0 ); @@ -903,9 +913,10 @@ substring_candidates( slapi_attr_init(&sattr, type); slapi_attr_assertion2keys_sub_sv( &sattr, initial, any, final, &ivals ); attr_done(&sattr); + 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 ); + pagedresults_set_unindexed( pb->pb_conn, pr_idx ); LDAPDebug( LDAP_DEBUG_TRACE, "<= sub_candidates ALLIDS (no keys)\n", 0, 0, 0 ); return( idl_allids( be ) ); @@ -919,7 +930,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 ); + pagedresults_set_unindexed( pb->pb_conn, 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 7d897c7..e6967e8 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_search.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c @@ -95,7 +95,7 @@ compute_lookthrough_limit( Slapi_PBlock *pb, struct ldbminfo *li ) } } - if (op && (op->o_flags & OP_FLAG_PAGED_RESULTS)) { + if (op_is_pagedresults(op)) { if ( slapi_reslimit_get_integer_limit( conn, li->li_reslimit_pagedlookthrough_handle, &limit ) != SLAPI_RESLIMIT_STATUS_SUCCESS ) { @@ -127,7 +127,7 @@ compute_allids_limit( Slapi_PBlock *pb, struct ldbminfo *li ) limit = li->li_allidsthreshold; PR_Unlock(li->li_config_mutex); } - if (op && (op->o_flags & OP_FLAG_PAGED_RESULTS)) { + if (op_is_pagedresults(op)) { if ( slapi_reslimit_get_integer_limit( conn, li->li_reslimit_pagedallids_handle, &limit ) != SLAPI_RESLIMIT_STATUS_SUCCESS ) { @@ -184,8 +184,10 @@ ldbm_back_search_cleanup(Slapi_PBlock *pb, 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); + 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); @@ -355,8 +357,8 @@ ldbm_back_search( Slapi_PBlock *pb ) if ( !txn.back_txn_txn ) { dblayer_txn_init( li, &txn ); - slapi_pblock_set( pb, SLAPI_TXN, txn.back_txn_txn ); - } + slapi_pblock_set( pb, SLAPI_TXN, txn.back_txn_txn ); + } inst = (ldbm_instance *) be->be_instance_info; @@ -829,6 +831,7 @@ ldbm_back_search( Slapi_PBlock *pb ) if ( NULL != candidates && ALLIDS( candidates )) { unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED; int ri = 0; + int pr_idx = -1; /* * Return error if nsslapd-require-index is set and @@ -850,7 +853,8 @@ ldbm_back_search( Slapi_PBlock *pb ) } slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote ); - pagedresults_set_unindexed( pb->pb_conn ); + slapi_pblock_get( pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx ); + pagedresults_set_unindexed( pb->pb_conn, pr_idx ); } sr->sr_candidates = candidates; @@ -1338,6 +1342,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension ) int rc = 0; int estimate = 0; /* estimated search result count */ back_txn txn = {NULL}; + int pr_idx = -1; slapi_pblock_get( pb, SLAPI_BACKEND, &be ); slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li ); @@ -1354,6 +1359,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension ) 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 ); if ( !txn.back_txn_txn ) { dblayer_txn_init( li, &txn ); @@ -1424,7 +1430,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension ) if ( slapi_op_abandoned( pb ) || (NULL == sr) ) { /* in case paged results, clean up the conn */ - pagedresults_set_search_result(pb->pb_conn, NULL, 0); + 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 ) { @@ -1441,7 +1447,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension ) if ( tlimit != -1 && curtime > stoptime ) { /* in case paged results, clean up the conn */ - pagedresults_set_search_result(pb->pb_conn, NULL, 0); + 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 ) { @@ -1458,7 +1464,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension ) if ( llimit != -1 && sr->sr_lookthroughcount >= llimit ) { /* in case paged results, clean up the conn */ - pagedresults_set_search_result(pb->pb_conn, NULL, 0); + 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 ) { @@ -1478,7 +1484,7 @@ 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); + 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 ) { @@ -1621,7 +1627,8 @@ 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); + 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 ); diff --git a/ldap/servers/slapd/back-ldbm/vlv.c b/ldap/servers/slapd/back-ldbm/vlv.c index a953030..cf807ec 100644 --- a/ldap/servers/slapd/back-ldbm/vlv.c +++ b/ldap/servers/slapd/back-ldbm/vlv.c @@ -1159,9 +1159,11 @@ vlv_search_build_candidate_list(Slapi_PBlock *pb, const Slapi_DN *base, int *vlv slapi_rwlock_rdlock(be->vlvSearchList_lock); if((pi=vlv_find_search(be, base, scope, fstr, sort_control)) == NULL) { unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED; + int pr_idx = -1; + 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 ); + pagedresults_set_unindexed( pb->pb_conn, 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/connection.c b/ldap/servers/slapd/connection.c index 13d56b6..9e43104 100644 --- a/ldap/servers/slapd/connection.c +++ b/ldap/servers/slapd/connection.c @@ -117,6 +117,8 @@ connection_done(Connection *conn) { PR_DestroyLock(conn->c_pdumutex); } + /* PAGED_RESULTS */ + pagedresults_cleanup_all(conn, 0); } /* @@ -2092,7 +2094,7 @@ void connection_enter_leave_turbo(Connection *conn, int current_turbo_flag, int PR_Lock(conn->c_mutex); /* We can already be in turbo mode, or not */ current_mode = current_turbo_flag; - if (conn->c_search_result_set) { + if (pagedresults_in_use(conn)) { /* PAGED_RESULTS does not need turbo mode */ new_mode = 0; } else if (conn->c_private->operation_rate == 0) { @@ -2776,7 +2778,9 @@ disconnect_server_nomutex( Connection *conn, PRUint64 opconnid, int opid, PRErro conn->c_gettingber = 0; connection_abandon_operations( conn ); - conn->c_timelimit = 0; /* needed here to ensure simple paged results timeout properly and don't impact subsequent ops */ + /* needed here to ensure simple paged results timeout properly and + * don't impact subsequent ops */ + pagedresults_reset_timedout(conn); if (! config_check_referral_mode()) { /* diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c index 3333e8a..922802c 100644 --- a/ldap/servers/slapd/daemon.c +++ b/ldap/servers/slapd/daemon.c @@ -1211,17 +1211,15 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps { int add_fd = 1; /* check timeout for PAGED RESULTS */ - if (c->c_current_be && (c->c_timelimit > 0)) + if (pagedresults_is_timedout(c)) { - time_t ctime = current_time(); - if (ctime > c->c_timelimit) - { - /* Exceeded the timelimit; disconnect the client */ - disconnect_server_nomutex(c, c->c_connid, -1, - SLAPD_DISCONNECT_IO_TIMEOUT, 0); - connection_table_move_connection_out_of_active_list(ct,c); - add_fd = 0; /* do not poll on this fd */ - } + /* Exceeded the timelimit; disconnect the client */ + disconnect_server_nomutex(c, c->c_connid, -1, + SLAPD_DISCONNECT_IO_TIMEOUT, + 0); + connection_table_move_connection_out_of_active_list(ct, + c); + add_fd = 0; /* do not poll on this fd */ } if (add_fd) { diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c index 0101469..8d3e590 100644 --- a/ldap/servers/slapd/opshared.c +++ b/ldap/servers/slapd/opshared.c @@ -268,6 +268,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result) Slapi_Backend *pr_be = NULL; void *pr_search_result = NULL; int pr_reset_processing = 0; + int pr_idx = -1; be_list[0] = NULL; referral_list[0] = NULL; @@ -450,28 +451,38 @@ op_shared_search (Slapi_PBlock *pb, int send_result) if ( slapi_control_present (ctrlp, LDAP_CONTROL_PAGEDRESULTS, &ctl_value, &iscritical) ) { - rc = pagedresults_parse_control_value(ctl_value, - &pagesize, &curr_search_count); + rc = pagedresults_parse_control_value(pb, ctl_value, + &pagesize, &pr_idx); + /* Let's set pr_idx even if it fails; in case, pr_idx == -1. */ + slapi_pblock_set(pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx); if (LDAP_SUCCESS == rc) { unsigned int opnote = SLAPI_OP_NOTE_SIMPLEPAGED; - if (pagedresults_check_or_set_processing(pb->pb_conn)) { + 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); + NULL, "Simple Paged Results Search " + "already in progress on this connection", + 0, NULL); goto free_and_return_nolock; } - pr_reset_processing = 1; /* need to reset after we are done with this op */ - operation->o_flags |= OP_FLAG_PAGED_RESULTS; - pr_be = pagedresults_get_current_be(pb->pb_conn); - pr_search_result = pagedresults_get_search_result(pb->pb_conn); + /* 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, + pr_idx); estimate = - pagedresults_get_search_result_set_size_estimate(pb->pb_conn); - if (pagedresults_get_unindexed(pb->pb_conn)) { + pagedresults_get_search_result_set_size_estimate(pb->pb_conn, + pr_idx); + if (pagedresults_get_unindexed(pb->pb_conn, pr_idx)) { opnote |= SLAPI_OP_NOTE_UNINDEXED; } slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote ); } else { /* parse paged-results-control failed */ if (iscritical) { /* return an error since it's critical */ + send_ldap_result(pb, rc, NULL, + "Simple Paged Results Search failed", + 0, NULL); goto free_and_return; } } @@ -567,7 +578,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result) } if (slapi_sdn_compare(basesdn, sdn)) { slapi_sdn_free(&basesdn); - basesdn = operation_get_target_spec(pb->pb_op); + basesdn = operation_get_target_spec(pb->pb_op); slapi_sdn_free(&basesdn); basesdn = slapi_sdn_dup(sdn); operation_set_target_spec (pb->pb_op, basesdn); @@ -601,13 +612,13 @@ op_shared_search (Slapi_PBlock *pb, int send_result) } /* set the timelimit to clean up the too-long-lived-paged results requests */ - if (operation->o_flags & OP_FLAG_PAGED_RESULTS) { + if (op_is_pagedresults(operation)) { time_t optime, time_up; int tlimit; 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); + pagedresults_set_timelimit(pb->pb_conn, time_up, pr_idx); } /* PAR: now filters have been rewritten, we can assign plugins to work on them */ @@ -658,7 +669,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result) next_be = NULL; } - if ((operation->o_flags & OP_FLAG_PAGED_RESULTS) && pr_search_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 ); @@ -666,7 +677,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result) /* 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); + pagedresults_set_search_result(pb->pb_conn, sr, 0, pr_idx); if (PAGEDRESULTS_SEARCH_END == pr_stat) { /* no more entries to send in the backend */ @@ -676,7 +687,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result) } else { curr_search_count = pnentries; /* no more entries, but at least another backend */ - if (pagedresults_set_current_be(pb->pb_conn, next_be) < 0) { + if (pagedresults_set_current_be(pb->pb_conn, next_be, pr_idx) < 0) { goto free_and_return; } } @@ -685,14 +696,16 @@ op_shared_search (Slapi_PBlock *pb, int send_result) curr_search_count = pnentries; estimate -= estimate?curr_search_count:0; } - pagedresults_set_response_control(pb, 0, estimate, curr_search_count); - if (pagedresults_get_with_sort(pb->pb_conn)) { + pagedresults_set_response_control(pb, 0, estimate, + curr_search_count, pr_idx); + if (pagedresults_get_with_sort(pb->pb_conn, pr_idx)) { sort_make_sort_response_control(pb, CONN_GET_SORT_RESULT_CODE, NULL); } - pagedresults_set_search_result_set_size_estimate(pb->pb_conn, estimate); + pagedresults_set_search_result_set_size_estimate(pb->pb_conn, + estimate, pr_idx); next_be = NULL; /* to break the loop */ if (curr_search_count == -1) { - pagedresults_cleanup(pb->pb_conn, 1 /* need to lock */); + pagedresults_free_one(pb->pb_conn, pr_idx); } } else { /* be_suffix null means that we are searching the default backend @@ -803,7 +816,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result) rc = send_results_ext (pb, 1, &pnentries, pagesize, &pr_stat); /* PAGED RESULTS */ - if (operation->o_flags & OP_FLAG_PAGED_RESULTS) { + if (op_is_pagedresults(operation)) { void *sr = NULL; int with_sort = operation->o_flags & OP_FLAG_SERVER_SIDE_SORTING; @@ -814,7 +827,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result) curr_search_count = -1; } else { /* no more entries, but at least another backend */ - if (pagedresults_set_current_be(pb->pb_conn, next_be) < 0) { + if (pagedresults_set_current_be(pb->pb_conn, next_be, pr_idx) < 0) { goto free_and_return; } } @@ -822,22 +835,22 @@ op_shared_search (Slapi_PBlock *pb, int send_result) 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) < 0 || - pagedresults_set_search_result(pb->pb_conn, sr, 0) < 0 || + 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) < 0 || + curr_search_count, pr_idx) < 0 || pagedresults_set_search_result_set_size_estimate(pb->pb_conn, - estimate) < 0 || - pagedresults_set_with_sort(pb->pb_conn, with_sort) < 0) { + estimate, pr_idx) < 0 || + pagedresults_set_with_sort(pb->pb_conn, with_sort, pr_idx) < 0) { goto free_and_return; } } - pagedresults_set_response_control(pb, 0, - estimate, curr_search_count); + 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_cleanup(pb->pb_conn, 1 /* need to lock */); + pagedresults_free_one(pb->pb_conn, pr_idx); } } @@ -965,7 +978,7 @@ free_and_return_nolock: slapi_ch_free_string(&proxydn); slapi_ch_free_string(&proxystr); if (pr_reset_processing) { - pagedresults_reset_processing(pb->pb_conn); + pagedresults_reset_processing(pb->pb_conn, pr_idx); } } @@ -1204,12 +1217,14 @@ iterate(Slapi_PBlock *pb, Slapi_Backend *be, int send_result, Slapi_Entry *e = NULL; char **attrs = NULL; unsigned int pr_stat = 0; + int pr_idx = -1; if ( NULL == pb ) { return rval; } slapi_pblock_get(pb, SLAPI_SEARCH_ATTRS, &attrs); slapi_pblock_get(pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly); + slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx); *pnentries = 0; @@ -1231,7 +1246,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); + pagedresults_set_timelimit(pb->pb_conn, 0, pr_idx); rval = -1; done = 1; continue; @@ -1542,7 +1557,7 @@ compute_limits (Slapi_PBlock *pb) } } - if (op && (op->o_flags & OP_FLAG_PAGED_RESULTS)) { + if (op_is_pagedresults(op)) { if ( slapi_reslimit_get_integer_limit( pb->pb_conn, pagedsizelimit_reslimit_handle, &max_sizelimit ) != SLAPI_RESLIMIT_STATUS_SUCCESS ) { @@ -1633,7 +1648,7 @@ send_results_ext(Slapi_PBlock *pb, int send_result, int *nentries, int pagesize, */ break; - case 1: /* everything is ok - don't send the result */ + case 1: /* everything is ok - don't send the result */ rc = 0; } diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c index c77ec27..1690e88 100644 --- a/ldap/servers/slapd/pagedresults.c +++ b/ldap/servers/slapd/pagedresults.c @@ -50,20 +50,29 @@ * -- requested page size from client * -- result set size estimate from server * cookie OCTET STRING + * -- index for the pagedresults array in the connection * } * * Return an LDAP error code (LDAP_SUCCESS if all goes well). */ int -pagedresults_parse_control_value( struct berval *psbvp, - ber_int_t *pagesize, int *curr_search_count ) +pagedresults_parse_control_value( Slapi_PBlock *pb, + struct berval *psbvp, ber_int_t *pagesize, + int *index ) { int rc = LDAP_SUCCESS; struct berval cookie = {0}; + Connection *conn = pb->pb_conn; + Operation *op = pb->pb_op; - if ( NULL == pagesize || NULL == curr_search_count ) { + LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_parse_control_value\n"); + if ( NULL == conn || NULL == op || NULL == pagesize || NULL == index ) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "<-- pagedresults_parse_control_value: %d\n", + LDAP_OPERATIONS_ERROR); return LDAP_OPERATIONS_ERROR; } + *index = -1; if ( psbvp->bv_len == 0 || psbvp->bv_val == NULL ) { @@ -85,19 +94,64 @@ pagedresults_parse_control_value( struct berval *psbvp, /* the ber encoding is no longer needed */ ber_free(ber, 1); if ( cookie.bv_len <= 0 ) { - *curr_search_count = 0; + int i; + int maxlen; + /* first time? */ + PR_Lock(conn->c_mutex); + maxlen = conn->c_pagedresults.prl_maxlen; + if (conn->c_pagedresults.prl_count == maxlen) { + if (0 == maxlen) { /* first time */ + conn->c_pagedresults.prl_maxlen = 1; + conn->c_pagedresults.prl_list = + (PagedResults *)slapi_ch_calloc(1, + sizeof(PagedResults)); + } else { + /* new max length */ + conn->c_pagedresults.prl_maxlen *= 2; + conn->c_pagedresults.prl_list = + (PagedResults *)slapi_ch_realloc( + (char *)conn->c_pagedresults.prl_list, + sizeof(PagedResults) * + conn->c_pagedresults.prl_maxlen); + /* initialze newly allocated area */ + memset(conn->c_pagedresults.prl_list + maxlen, '\0', + sizeof(PagedResults) * maxlen); + } + *index = maxlen; /* the first position in the new area */ + } else { + for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) { + if (!conn->c_pagedresults.prl_list[i].pr_current_be) { + *index = i; + break; + } + } + } + conn->c_pagedresults.prl_count++; + PR_Unlock(conn->c_mutex); } else { - /* not an error */ + /* Repeated paged results request. + * PagedResults is already allocated. */ char *ptr = slapi_ch_malloc(cookie.bv_len + 1); memcpy(ptr, cookie.bv_val, cookie.bv_len); *(ptr+cookie.bv_len) = '\0'; - *curr_search_count = strtol(ptr, NULL, 10); + *index = strtol(ptr, NULL, 10); slapi_ch_free_string(&ptr); } slapi_ch_free((void **)&cookie.bv_val); } } + if ((*index > -1) && (*index < conn->c_pagedresults.prl_maxlen)) { + /* Need to keep the latest msgid to prepare for the abandon. */ + conn->c_pagedresults.prl_list[*index].pr_msgid = op->o_msgid; + } else { + rc = LDAP_PROTOCOL_ERROR; + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "pagedresults_parse_control_value: invalid cookie: %d\n", + *index); + } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_parse_control_value: idx %d\n", *index); return rc; } @@ -114,7 +168,8 @@ pagedresults_parse_control_value( struct berval *psbvp, */ void pagedresults_set_response_control( Slapi_PBlock *pb, int iscritical, - ber_int_t estimate, int curr_search_count ) + ber_int_t estimate, int current_search_count, + int index ) { LDAPControl **resultctrls = NULL; LDAPControl pr_respctrl; @@ -124,16 +179,19 @@ pagedresults_set_response_control( Slapi_PBlock *pb, int iscritical, int found = 0; int i; + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_set_response_control: idx=%d\n", index); + if ( (ber = der_alloc()) == NULL ) { goto bailout; } /* begin sequence, payload, end sequence */ - if (curr_search_count < 0) { + if (current_search_count < 0) { cookie_str = slapi_ch_strdup(""); } else { - cookie_str = slapi_ch_smprintf("%d", curr_search_count); + cookie_str = slapi_ch_smprintf("%d", index); } ber_printf ( ber, "{io}", estimate, cookie_str, strlen(cookie_str) ); if ( ber_flatten ( ber, &berval ) != LDAP_SUCCESS ) @@ -169,202 +227,362 @@ pagedresults_set_response_control( Slapi_PBlock *pb, int iscritical, bailout: slapi_ch_free_string(&cookie_str); - ber_free ( ber, 1 ); /* ber_free() checks for NULL param */ + ber_free ( ber, 1 ); /* ber_free() checks for NULL param */ ber_bvfree ( berval ); /* ber_bvfree() checks for NULL param */ + + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_set_response_control: idx=%d\n", index); +} + +int +pagedresults_free_one( Connection *conn, int index ) +{ + int rc = -1; + + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_free_one: idx=%d\n", index); + if (conn && (index > -1)) { + PR_Lock(conn->c_mutex); + if (conn->c_pagedresults.prl_count <= 0) { + LDAPDebug2Args(LDAP_DEBUG_TRACE, "pagedresults_free_one: " + "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) { + memset(&conn->c_pagedresults.prl_list[index], + '\0', sizeof(PagedResults)); + conn->c_pagedresults.prl_count--; + rc = 0; + } + PR_Unlock(conn->c_mutex); + } + + LDAPDebug1Arg(LDAP_DEBUG_TRACE, "<-- pagedresults_free_one: %d\n", rc); + return rc; +} + +int +pagedresults_free_one_msgid( Connection *conn, ber_int_t msgid ) +{ + int rc = -1; + int i; + + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_free_one: idx=%d\n", index); + if (conn && (index > -1)) { + PR_Lock(conn->c_mutex); + if (conn->c_pagedresults.prl_count <= 0) { + LDAPDebug2Args(LDAP_DEBUG_TRACE, "pagedresults_free_one_msgid: " + "conn=%d paged requests list count is %d\n", + conn->c_connid, conn->c_pagedresults.prl_count); + } else { + for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) { + if (conn->c_pagedresults.prl_list[i].pr_msgid == msgid) { + memset(&conn->c_pagedresults.prl_list[i], + '\0', sizeof(PagedResults)); + conn->c_pagedresults.prl_count--; + rc = 0; + break; + } + } + } + PR_Unlock(conn->c_mutex); + } + + LDAPDebug1Arg(LDAP_DEBUG_TRACE, "<-- pagedresults_free_one: %d\n", rc); + return rc; } /* setters and getters for the connection */ Slapi_Backend * -pagedresults_get_current_be(Connection *conn) +pagedresults_get_current_be(Connection *conn, int index) { Slapi_Backend *be = NULL; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_get_current_be: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - be = conn->c_current_be; + if (index < conn->c_pagedresults.prl_maxlen) { + be = conn->c_pagedresults.prl_list[index].pr_current_be; + } PR_Unlock(conn->c_mutex); } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_get_current_be: %p\n", be); return be; } int -pagedresults_set_current_be(Connection *conn, Slapi_Backend *be) +pagedresults_set_current_be(Connection *conn, Slapi_Backend *be, int index) { int rc = -1; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_set_current_be: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - conn->c_current_be = be; + if (index < conn->c_pagedresults.prl_maxlen) { + conn->c_pagedresults.prl_list[index].pr_current_be = be; + } PR_Unlock(conn->c_mutex); rc = 0; } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_set_current_be: %d\n", rc); return rc; } void * -pagedresults_get_search_result(Connection *conn) +pagedresults_get_search_result(Connection *conn, int index) { void *sr = NULL; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_get_search_result: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - sr = conn->c_search_result_set; + if (index < conn->c_pagedresults.prl_maxlen) { + sr = conn->c_pagedresults.prl_list[index].pr_search_result_set; + } PR_Unlock(conn->c_mutex); } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_get_search_result: %p\n", sr); return sr; } int -pagedresults_set_search_result(Connection *conn, void *sr, int locked) +pagedresults_set_search_result(Connection *conn, void *sr, + int locked, int index) { int rc = -1; - if (conn) { + 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); - conn->c_search_result_set = sr; + if (index < conn->c_pagedresults.prl_maxlen) { + conn->c_pagedresults.prl_list[index].pr_search_result_set = sr; + } if (!locked) PR_Unlock(conn->c_mutex); rc = 0; } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_set_search_result: %d\n", rc); return rc; } int -pagedresults_get_search_result_count(Connection *conn) +pagedresults_get_search_result_count(Connection *conn, int index) { int count = 0; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_get_search_result_count: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - count = conn->c_search_result_count; + if (index < conn->c_pagedresults.prl_maxlen) { + count = conn->c_pagedresults.prl_list[index].pr_search_result_count; + } PR_Unlock(conn->c_mutex); } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_get_search_result_count: %d\n", count); return count; } int -pagedresults_set_search_result_count(Connection *conn, int count) +pagedresults_set_search_result_count(Connection *conn, int count, int index) { int rc = -1; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_set_search_result_count: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - conn->c_search_result_count = count; + if (index < conn->c_pagedresults.prl_maxlen) { + conn->c_pagedresults.prl_list[index].pr_search_result_count = count; + } PR_Unlock(conn->c_mutex); rc = 0; } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_set_search_result_count: %d\n", rc); return rc; } int -pagedresults_get_search_result_set_size_estimate(Connection *conn) +pagedresults_get_search_result_set_size_estimate(Connection *conn, int index) { int count = 0; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_get_search_result_set_size_estimate: " + "idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - count = conn->c_search_result_set_size_estimate; + if (index < conn->c_pagedresults.prl_maxlen) { + count = conn->c_pagedresults.prl_list[index].pr_search_result_set_size_estimate; + } PR_Unlock(conn->c_mutex); } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_get_search_result_set_size_estimate: %d\n", + count); return count; } int -pagedresults_set_search_result_set_size_estimate(Connection *conn, int count) +pagedresults_set_search_result_set_size_estimate(Connection *conn, + int count, int index) { int rc = -1; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_set_search_result_set_size_estimate: " + "idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - conn->c_search_result_set_size_estimate = count; + if (index < conn->c_pagedresults.prl_maxlen) { + conn->c_pagedresults.prl_list[index].pr_search_result_set_size_estimate = count; + } PR_Unlock(conn->c_mutex); rc = 0; } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_set_search_result_set_size_estimate: %d\n", + rc); return rc; } int -pagedresults_get_with_sort(Connection *conn) +pagedresults_get_with_sort(Connection *conn, int index) { int flags = 0; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_get_with_sort: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - flags = conn->c_flags&CONN_FLAG_PAGEDRESULTS_WITH_SORT; + if (index < conn->c_pagedresults.prl_maxlen) { + flags = conn->c_pagedresults.prl_list[index].pr_flags&CONN_FLAG_PAGEDRESULTS_WITH_SORT; + } PR_Unlock(conn->c_mutex); } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_get_with_sort: %p\n", flags); return flags; } int -pagedresults_set_with_sort(Connection *conn, int flags) +pagedresults_set_with_sort(Connection *conn, int flags, int index) { int rc = -1; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_set_with_sort: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - if (flags & OP_FLAG_SERVER_SIDE_SORTING) - conn->c_flags |= CONN_FLAG_PAGEDRESULTS_WITH_SORT; + if (index < conn->c_pagedresults.prl_maxlen) { + if (flags & OP_FLAG_SERVER_SIDE_SORTING) { + conn->c_pagedresults.prl_list[index].pr_flags |= + CONN_FLAG_PAGEDRESULTS_WITH_SORT; + } + } PR_Unlock(conn->c_mutex); rc = 0; } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, "<-- pagedresults_set_with_sort: %d\n", rc); return rc; } int -pagedresults_get_unindexed(Connection *conn) +pagedresults_get_unindexed(Connection *conn, int index) { int flags = 0; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_get_unindexed: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - flags = conn->c_flags&CONN_FLAG_PAGEDRESULTS_UNINDEXED; + if (index < conn->c_pagedresults.prl_maxlen) { + flags = conn->c_pagedresults.prl_list[index].pr_flags&CONN_FLAG_PAGEDRESULTS_UNINDEXED; + } PR_Unlock(conn->c_mutex); } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_get_unindexed: %p\n", flags); return flags; } int -pagedresults_set_unindexed(Connection *conn) +pagedresults_set_unindexed(Connection *conn, int index) { int rc = -1; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_set_unindexed: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - conn->c_flags |= CONN_FLAG_PAGEDRESULTS_UNINDEXED; + if (index < conn->c_pagedresults.prl_maxlen) { + conn->c_pagedresults.prl_list[index].pr_flags |= + CONN_FLAG_PAGEDRESULTS_UNINDEXED; + } PR_Unlock(conn->c_mutex); rc = 0; } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_set_unindexed: %d\n", rc); return rc; } int -pagedresults_get_sort_result_code(Connection *conn) +pagedresults_get_sort_result_code(Connection *conn, int index) { - int code = 0; - if (conn) { + int code = LDAP_OPERATIONS_ERROR; + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_get_sort_result_code: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - code = conn->c_sort_result_code; + if (index < conn->c_pagedresults.prl_maxlen) { + code = conn->c_pagedresults.prl_list[index].pr_sort_result_code; + } PR_Unlock(conn->c_mutex); } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_get_sort_result_code: %d\n", code); return code; } int -pagedresults_set_sort_result_code(Connection *conn, int code) +pagedresults_set_sort_result_code(Connection *conn, int code, int index) { int rc = -1; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_set_sort_result_code: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - conn->c_sort_result_code = code; + if (index < conn->c_pagedresults.prl_maxlen) { + conn->c_pagedresults.prl_list[index].pr_sort_result_code = code; + } PR_Unlock(conn->c_mutex); rc = 0; } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_set_sort_result_code: %d\n", rc); return rc; } int -pagedresults_set_timelimit(Connection *conn, time_t timelimit) +pagedresults_set_timelimit(Connection *conn, time_t timelimit, int index) { int rc = -1; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_set_timelimit: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - conn->c_timelimit = timelimit; + if (index < conn->c_pagedresults.prl_maxlen) { + conn->c_pagedresults.prl_list[index].pr_timelimit = timelimit; + } PR_Unlock(conn->c_mutex); rc = 0; } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, "<-- pagedresults_set_timelimit: %d\n", rc); return rc; } /* - * must be called with conn->c_mutex held + * pagedresults_cleanup cleans up the pagedresults list; + * it does not free the list. * return values * 0: not a simple paged result connection * 1: simple paged result and successfully abandoned @@ -373,26 +591,76 @@ int pagedresults_cleanup(Connection *conn, int needlock) { int rc = 0; + int i; + PagedResults *prp = NULL; + + LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_cleanup\n"); + + if (NULL == conn) { + LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_cleanup: -\n"); + return 0; + } if (needlock) { PR_Lock(conn->c_mutex); } - if (conn->c_current_be) { - if (conn->c_search_result_set) { - if (conn->c_current_be->be_search_results_release) { - conn->c_current_be->be_search_results_release(&(conn->c_search_result_set)); - } - conn->c_search_result_set = NULL; + 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_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)); + rc = 1; + } + memset(prp, '\0', sizeof(PagedResults)); + } + conn->c_pagedresults.prl_count = 0; + if (needlock) { + PR_Unlock(conn->c_mutex); + } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, "<-- pagedresults_cleanup: %d\n", rc); + return rc; +} + +/* + * pagedresults_cleanup_all frees the list. + * return values + * 0: not a simple paged result connection + * 1: simple paged result and successfully abandoned + */ +int +pagedresults_cleanup_all(Connection *conn, int needlock) +{ + int rc = 0; + int i; + PagedResults *prp = NULL; + + LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_cleanup_all\n"); + + if (NULL == conn) { + LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_cleanup_all: -\n"); + return 0; + } + + if (needlock) { + PR_Lock(conn->c_mutex); + } + 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_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)); + rc = 1; } - conn->c_current_be = 0; - rc = 1; } - conn->c_search_result_count = 0; - conn->c_timelimit = 0; - conn->c_flags &= ~CONN_FLAG_PAGEDRESULTS_PROCESSING; + slapi_ch_free((void **)&conn->c_pagedresults.prl_list); + conn->c_pagedresults.prl_maxlen = 0; + conn->c_pagedresults.prl_count = 0; if (needlock) { PR_Unlock(conn->c_mutex); } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, "<-- pagedresults_cleanup_all: %d\n", rc); return rc; } @@ -402,16 +670,24 @@ pagedresults_cleanup(Connection *conn, int needlock) * mark that it is processing, and return False */ int -pagedresults_check_or_set_processing(Connection *conn) +pagedresults_check_or_set_processing(Connection *conn, int index) { int ret = 0; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_check_or_set_processing\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - ret = conn->c_flags&CONN_FLAG_PAGEDRESULTS_PROCESSING; - /* if ret is true, the following doesn't do anything */ - conn->c_flags |= CONN_FLAG_PAGEDRESULTS_PROCESSING; + if (index < conn->c_pagedresults.prl_maxlen) { + ret = (conn->c_pagedresults.prl_list[index].pr_flags & + CONN_FLAG_PAGEDRESULTS_PROCESSING); + /* if ret is true, the following doesn't do anything */ + conn->c_pagedresults.prl_list[index].pr_flags |= + CONN_FLAG_PAGEDRESULTS_PROCESSING; + } PR_Unlock(conn->c_mutex); } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_check_or_set_processing: %d\n", ret); return ret; } @@ -421,15 +697,109 @@ pagedresults_check_or_set_processing(Connection *conn) * False otherwise */ int -pagedresults_reset_processing(Connection *conn) +pagedresults_reset_processing(Connection *conn, int index) { int ret = 0; - if (conn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "--> pagedresults_reset_processing: idx=%d\n", index); + if (conn && (index > -1)) { PR_Lock(conn->c_mutex); - ret = conn->c_flags&CONN_FLAG_PAGEDRESULTS_PROCESSING; - /* if ret is false, the following doesn't do anything */ - conn->c_flags &= ~CONN_FLAG_PAGEDRESULTS_PROCESSING; + if (index < conn->c_pagedresults.prl_maxlen) { + ret = (conn->c_pagedresults.prl_list[index].pr_flags & + CONN_FLAG_PAGEDRESULTS_PROCESSING); + /* if ret is false, the following doesn't do anything */ + conn->c_pagedresults.prl_list[index].pr_flags &= + ~CONN_FLAG_PAGEDRESULTS_PROCESSING; + } PR_Unlock(conn->c_mutex); } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "<-- pagedresults_reset_processing: %d\n", ret); return ret; } + +/* Are all the paged results requests timed out? */ +int +pagedresults_is_timedout(Connection *conn) +{ + int i; + PagedResults *prp = NULL; + time_t ctime; + int rc = 0; + + LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_is_timedout\n"); + + if (NULL == conn || 0 == conn->c_pagedresults.prl_count) { + LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_is_timedout: -\n"); + return rc; + } + + ctime = current_time(); + for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) { + prp = conn->c_pagedresults.prl_list + i; + if (prp->pr_current_be && (prp->pr_timelimit > 0)) { + if (ctime < prp->pr_timelimit) { + LDAPDebug0Args(LDAP_DEBUG_TRACE, + "<-- pagedresults_is_timedout: 0\n"); + return 0; /* at least, one request is not timed out. */ + } else { + rc = 1; /* possibly timed out */ + } + } + } + LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_is_timedout: 1\n"); + return rc; /* all requests are timed out. */ +} + +/* reset all timeout */ +int +pagedresults_reset_timedout(Connection *conn) +{ + int i; + PagedResults *prp = NULL; + + LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_reset_timedout\n"); + if (NULL == conn) { + LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_reset_timedout: -\n"); + return 0; + } + + for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) { + prp = conn->c_pagedresults.prl_list + i; + prp->pr_timelimit = 0; + } + LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_reset_timedout: 0\n"); + return 0; +} + +/* paged results requests are in progress. */ +int +pagedresults_in_use(Connection *conn) +{ + LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_in_use\n"); + if (NULL == conn) { + LDAPDebug0Args(LDAP_DEBUG_TRACE, "<-- pagedresults_in_use: -\n"); + return 0; + } + LDAPDebug1Arg(LDAP_DEBUG_TRACE, "<-- pagedresults_in_use: %d\n", + conn->c_pagedresults.prl_count); + return conn->c_pagedresults.prl_count; +} + +int +op_is_pagedresults(Operation *op) +{ + if (NULL == op) { + return 0; + } + return op->o_flags & OP_FLAG_PAGED_RESULTS; +} + +void +op_set_pagedresults(Operation *op) +{ + if (NULL == op) { + return; + } + op->o_flags |= OP_FLAG_PAGED_RESULTS; +} diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c index 2a1c706..4b54403 100644 --- a/ldap/servers/slapd/pblock.c +++ b/ldap/servers/slapd/pblock.c @@ -1925,6 +1925,14 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value ) (*(void **)value) = pblock->pb_syntax_filter_data; break; + case SLAPI_PAGED_RESULTS_INDEX: + if (op_is_pagedresults(pblock->pb_op)) { + /* search req is simple paged results */ + (*(int *)value) = pblock->pb_paged_results_index; + } else { + (*(int *)value) = -1; + } + break; default: LDAPDebug( LDAP_DEBUG_ANY, "Unknown parameter block argument %d\n", arg, 0, 0 ); @@ -3459,6 +3467,10 @@ slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value ) pblock->pb_syntax_filter_data = (void *)value; break; + case SLAPI_PAGED_RESULTS_INDEX: + pblock->pb_paged_results_index = *(int *)value; + break; + default: LDAPDebug( LDAP_DEBUG_ANY, "Unknown parameter block argument %d\n", arg, 0, 0 ); diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index d7057a1..ad66595 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -1378,26 +1378,40 @@ int slapd_do_all_nss_ssl_init(int slapd_exemode, int importexport_encrypt, /* * pagedresults.c */ -int pagedresults_parse_control_value(struct berval *psbvp, ber_int_t *pagesize, int *curr_search_count); -void pagedresults_set_response_control(Slapi_PBlock *pb, int iscritical, ber_int_t estimate, int curr_search_count); -Slapi_Backend *pagedresults_get_current_be(Connection *conn); -int pagedresults_set_current_be(Connection *conn, Slapi_Backend *be); -void *pagedresults_get_search_result(Connection *conn); -int pagedresults_set_search_result(Connection *conn, void *sr, int locked); -int pagedresults_get_search_result_count(Connection *conn); -int pagedresults_set_search_result_count(Connection *conn, int cnt); -int pagedresults_get_search_result_set_size_estimate(Connection *conn); -int pagedresults_set_search_result_set_size_estimate(Connection *conn, int cnt); -int pagedresults_get_with_sort(Connection *conn); -int pagedresults_set_with_sort(Connection *conn, int flags); -int pagedresults_get_unindexed(Connection *conn); -int pagedresults_set_unindexed(Connection *conn); -int pagedresults_get_sort_result_code(Connection *conn); -int pagedresults_set_sort_result_code(Connection *conn, int code); -int pagedresults_set_timelimit(Connection *conn, time_t timelimit); +int pagedresults_parse_control_value(Slapi_PBlock *pb, struct berval *psbvp, + ber_int_t *pagesize, int *index); +void pagedresults_set_response_control(Slapi_PBlock *pb, int iscritical, + ber_int_t estimate, + 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, + 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 index); +int pagedresults_set_search_result_set_size_estimate(Connection *conn, 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_cleanup(Connection *conn, int needlock); -int pagedresults_check_or_set_processing(Connection *conn); -int pagedresults_reset_processing(Connection *conn); +int pagedresults_check_or_set_processing(Connection *conn, int index); +int pagedresults_reset_processing(Connection *conn, int index); +int pagedresults_is_timedout(Connection *conn); +int pagedresults_reset_timedout(Connection *conn); +int pagedresults_in_use(Connection *conn); +int pagedresults_free_one(Connection *conn, int index); +int op_is_pagedresults(Operation *op); +int pagedresults_cleanup_all(Connection *conn, int needlock); +void op_set_pagedresults(Operation *op); + /* * sort.c diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c index a3fff38..c84d44b 100644 --- a/ldap/servers/slapd/result.c +++ b/ldap/servers/slapd/result.c @@ -1426,8 +1426,7 @@ send_ldap_search_entry_ext( ber = NULL; /* flush_ber will always free the ber */ log_and_return: - if ( logit && operation_is_flag_set(operation, - OP_FLAG_ACTION_LOG_ACCESS)){ + if ( logit && operation_is_flag_set(operation, OP_FLAG_ACTION_LOG_ACCESS)) { log_entry( op, e ); diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index 3e63f11..025f749 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -1351,6 +1351,26 @@ typedef struct op { client (or we tried to do so and failed) */ + +/* simple paged structure */ +typedef struct _paged_results { + Slapi_Backend *pr_current_be; /* backend being used */ + void *pr_search_result_set; /* search result set for paging */ + int pr_search_result_count; /* search result count */ + int pr_search_result_set_size_estimate; /* estimated search result set size */ + int pr_sort_result_code; /* sort result put in response */ + time_t pr_timelimit; /* time limit for this request */ + int pr_flags; + ber_int_t pr_msgid; /* msgid of the request; to abandon */ +} PagedResults; + +/* array of simple paged structure stashed in connection */ +typedef struct _paged_results_list { + int prl_maxlen; /* size of the PagedResults array */ + int prl_count; /* count of the list in use */ + PagedResults *prl_list; /* pointer to pr_maxlen length PageResults array */ +} PagedResultsList; + /* * represents a connection from an ldap client */ @@ -1406,14 +1426,7 @@ typedef struct conn { int c_local_valid; /* flag true if the uid/gid are valid */ uid_t c_local_uid; /* uid of connecting process */ gid_t c_local_gid; /* gid of connecting process */ - /* PAGED_RESULTS */ - Slapi_Backend *c_current_be; /* backend being used */ - void *c_search_result_set; /* search result set for paging */ - int c_search_result_count; /* search result count */ - int c_search_result_set_size_estimate; /* estimated search result set size */ - int c_sort_result_code; /* sort result put in response */ - time_t c_timelimit; /* time limit for this connection */ - /* PAGED_RESULTS ENDS */ + PagedResultsList c_pagedresults; /* PAGED_RESULTS */ /* IO layer push/pop */ Conn_IO_Layer_cb c_push_io_layer_cb; /* callback to push an IO layer on the conn->c_prfd */ Conn_IO_Layer_cb c_pop_io_layer_cb; /* callback to pop an IO layer off of the conn->c_prfd */ @@ -1637,6 +1650,7 @@ typedef struct slapi_pblock { IFP pb_mr_index_sv_fn; /* values and keys are Slapi_Value ** */ int pb_syntax_filter_normalized; /* the syntax filter types/values are already normalized */ void *pb_syntax_filter_data; /* extra data to pass to a syntax plugin function */ + int pb_paged_results_index; /* stash SLAPI_PAGED_RESULTS_INDEX */ } slapi_pblock; /* index if substrlens */ diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index b4eb2a6..67d7ac9 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -6674,6 +6674,9 @@ typedef struct slapi_plugindesc { /* Size of the database, in kilobytes */ #define SLAPI_DBSIZE 199 +/* Simple paged results index */ +#define SLAPI_PAGED_RESULTS_INDEX 1945 + /* convenience macros for checking modify operation types */ #define SLAPI_IS_MOD_ADD(x) (((x) & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) #define SLAPI_IS_MOD_DELETE(x) (((x) & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) diff --git a/ldap/servers/slapd/sort.c b/ldap/servers/slapd/sort.c index b6814b2..903fa6f 100644 --- a/ldap/servers/slapd/sort.c +++ b/ldap/servers/slapd/sort.c @@ -53,14 +53,17 @@ sort_make_sort_response_control ( Slapi_PBlock *pb, int code, char *error_type) struct berval *bvp = NULL; int rc = -1; ber_int_t control_code; + int pr_idx = -1; + + 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); + code = pagedresults_get_sort_result_code(pb->pb_conn, pr_idx); } else { Slapi_Operation *operation; slapi_pblock_get (pb, SLAPI_OPERATION, &operation); - if (operation->o_flags & OP_FLAG_PAGED_RESULTS) { - pagedresults_set_sort_result_code(pb->pb_conn, code); + if (op_is_pagedresults(operation)) { + pagedresults_set_sort_result_code(pb->pb_conn, code, pr_idx); } }