| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- /** BEGIN COPYRIGHT BLOCK
- * This Program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; version 2 of the License.
- *
- * This Program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * In addition, as a special exception, Red Hat, Inc. gives You the additional
- * right to link the code of this Program with code not covered under the GNU
- * General Public License ("Non-GPL Code") and to distribute linked combinations
- * including the two, subject to the limitations in this paragraph. Non-GPL Code
- * permitted under this exception must only link to the code of this Program
- * through those well defined interfaces identified in the file named EXCEPTION
- * found in the source code files (the "Approved Interfaces"). The files of
- * Non-GPL Code may instantiate templates or use macros or inline functions from
- * the Approved Interfaces without causing the resulting work to be covered by
- * the GNU General Public License. Only Red Hat, Inc. may make changes or
- * additions to the list of Approved Interfaces. You must obey the GNU General
- * Public License in all respects for all of the Program code and other code used
- * in conjunction with the Program except the Non-GPL Code covered by this
- * exception. If you modify this file, you may extend this exception to your
- * version of the file, but you are not obligated to do so. If you do not wish to
- * provide this exception without modification, you must delete this exception
- * statement from your version and license this file solely under the GPL without
- * exception.
- *
- *
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- /* seq.c - ldbm backend sequential access function */
- #include "back-ldbm.h"
- #define SEQ_LITTLE_BUFFER_SIZE 100
- /*
- * Access the database sequentially.
- * There are 4 ways to call this routine. In each case, the equality index
- * for "attrname" is consulted:
- * 1) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_FIRST, then this routine
- * will find the smallest key greater than or equal to the SLAPI_SEQ_VAL
- * parameter, and return all entries that key's IDList. If SLAPI_SEQ_VAL
- * is NULL, then the smallest key is retrieved and the associaated
- * entries are returned.
- * 2) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_NEXT, then this routine
- * will find the smallest key strictly greater than the SLAPI_SEQ_VAL
- * parameter, and return all entries that key's IDList.
- * 3) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_PREV, then this routine
- * will find the greatest key strictly less than the SLAPI_SEQ_VAL
- * parameter, and return all entries that key's IDList.
- * 4) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_LAST, then this routine
- * will find the largest equality key in the index and return all entries
- * which match that key. The SLAPI_SEQ_VAL parameter is ignored.
- */
- int
- ldbm_back_seq( Slapi_PBlock *pb )
- {
- backend *be;
- ldbm_instance *inst;
- struct ldbminfo *li;
- IDList *idl = NULL;
- int err = LDAP_SUCCESS;
- DB *db;
- DBC *dbc = NULL;
- int type;
- char *attrname, *val;
- int isroot;
- struct attrinfo *ai = NULL;
- int return_value = -1;
- int nentries = 0;
- int retry_count=0;
- /* Decode arguments */
- slapi_pblock_get( pb, SLAPI_BACKEND, &be);
- slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
- slapi_pblock_get( pb, SLAPI_SEQ_TYPE, &type );
- slapi_pblock_get( pb, SLAPI_SEQ_ATTRNAME, &attrname );
- slapi_pblock_get( pb, SLAPI_SEQ_VAL, &val );
- slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
- inst = (ldbm_instance *) be->be_instance_info;
- /* Validate arguments */
- if ( type != SLAPI_SEQ_FIRST &&
- type != SLAPI_SEQ_LAST &&
- type != SLAPI_SEQ_NEXT &&
- type != SLAPI_SEQ_PREV )
- {
- slapi_send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
- "Bad seq access type", 0, NULL );
- return( -1 );
- }
- /* get a database */
- ainfo_get( be, attrname, &ai );
- LDAPDebug( LDAP_DEBUG_ARGS,
- " seq: indextype: %s indexmask: 0x%x seek type: %d\n",
- ai->ai_type, ai->ai_indexmask, type );
- if ( ! (INDEX_EQUALITY & ai->ai_indexmask) ) {
- LDAPDebug( LDAP_DEBUG_TRACE,
- "seq: caller specified un-indexed attribute %s\n",
- attrname ? attrname : "", 0, 0 );
- slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
- "Unindexed seq access type", 0, NULL );
- return -1;
- }
- if ( (return_value = dblayer_get_index_file( be, ai, &db, DBOPEN_CREATE )) != 0 ) {
- LDAPDebug( LDAP_DEBUG_ANY,
- "<= ldbm_back_seq NULL (could not open index file for attribute %s)\n",
- attrname, 0, 0 );
- slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
- return -1;
- }
- /* First, get a database cursor */
- return_value = db->cursor(db,NULL,&dbc,0);
- if (0 == return_value)
- {
- DBT data = {0};
- DBT key = {0};
- char little_buffer[SEQ_LITTLE_BUFFER_SIZE];
- char *big_buffer = NULL;
- char keystring = EQ_PREFIX;
- /* Set data */
- data.flags = DB_DBT_MALLOC;
- /* Set up key */
- key.flags = DB_DBT_MALLOC;
- if (NULL == val)
- {
- /* this means, goto the first equality key */
- /* seek to key >= "=" */
- key.data = &keystring;
- key.size = 1;
- }
- else
- {
- size_t key_length = strlen(val) + 2;
- if (key_length <= SEQ_LITTLE_BUFFER_SIZE) {
- key.data = &little_buffer;
- } else {
- big_buffer = slapi_ch_malloc(key_length);
- if (NULL == big_buffer) {
- /* memory allocation failure */
- dblayer_release_index_file( be, ai, db );
- return -1;
- }
- key.data = big_buffer;
- }
- key.size = sprintf(key.data,"%c%s",EQ_PREFIX,val);
- }
- /* decide which type of operation we're being asked to do and do the db bit */
- /* The c_get call always mallocs memory for data.data */
- /* The c_get call mallocs memory for key.data, except for DB_SET */
- /* after this, we leave data containing the retrieved IDL, or NULL if we didn't get it */
- switch (type) {
- case SLAPI_SEQ_FIRST:
- /* if (NULL == val) goto the first equality key ( seek to key >= "=" ) */
- /* else goto the first equality key >= val ( seek to key >= "=val" )*/
- return_value = dbc->c_get(dbc,&key,&data,DB_SET_RANGE);
- break;
- case SLAPI_SEQ_NEXT:
- /* seek to the indicated =value, then seek to the next entry, */
- return_value = dbc->c_get(dbc,&key,&data,DB_SET);
- if (0 == return_value)
- {
- slapi_ch_free(&(data.data));
- return_value = dbc->c_get(dbc,&key,&data,DB_NEXT);
- }
- else
- {
- /* DB_SET doesn't allocate key data. Make sure we don't try to free it... */
- key.data= NULL;
- }
- break;
- case SLAPI_SEQ_PREV:
- /* seek to the indicated =value, then seek to the previous entry, */
- return_value = dbc->c_get(dbc,&key,&data,DB_SET);
- if (0 == return_value )
- {
- slapi_ch_free(&(data.data));
- return_value = dbc->c_get(dbc,&key,&data,DB_PREV);
- }
- else
- {
- /* DB_SET doesn't allocate key data. Make sure we don't try to free it... */
- key.data= NULL;
- }
- break;
- case SLAPI_SEQ_LAST:
- /* seek to the first possible key after all the equality keys (">"), then seek back one */
- {
- keystring = EQ_PREFIX + 1;
- key.data = &keystring;
- key.size = 1;
- return_value = dbc->c_get(dbc,&key,&data,DB_SET_RANGE);
- if (0 == return_value || DB_NOTFOUND == return_value)
- {
- slapi_ch_free(&(data.data));
- return_value = dbc->c_get(dbc,&key,&data,DB_PREV);
- }
- }
- break;
- default:
- PR_ASSERT(0);
- }
- dbc->c_close(dbc);
- if (0 == return_value && key.data!=NULL)
- {
- /* Now check that the key we eventually settled on was an equality key ! */
- if (*((char*)key.data) == EQ_PREFIX)
- {
- /* Retrieve the idlist for this key */
- key.flags = 0;
- for (retry_count = 0; retry_count < IDL_FETCH_RETRY_COUNT; retry_count++) {
- err = NEW_IDL_DEFAULT;
- idl = idl_fetch( be, db, &key, NULL, ai, &err );
- if(err == DB_LOCK_DEADLOCK) {
- ldbm_nasty("ldbm_back_seq deadlock retry", 1600, err);
- continue;
- } else {
- break;
- }
- }
- }
- }
- if(retry_count == IDL_FETCH_RETRY_COUNT) {
- ldbm_nasty("ldbm_back_seq retry count exceeded",1645,err);
- } else if ( err != 0 && err != DB_NOTFOUND ) {
- ldbm_nasty("ldbm_back_seq database error", 1650, err);
- }
- slapi_ch_free( &(data.data) );
- if ( key.data != little_buffer && key.data != &keystring ) {
- slapi_ch_free( &(key.data) );
- }
- slapi_ch_free_string( &big_buffer );
- }
- /* null idlist means there were no matching keys */
- if ( idl != NULL )
- {
- /*
- * Step through the IDlist. For each ID, get the entry
- * and send it.
- */
- ID id;
- struct backentry *e;
- for ( id = idl_firstid( idl ); id != NOID;
- id = idl_nextid( idl, id ))
- {
- if (( e = id2entry( be, id, NULL, &err )) == NULL )
- {
- if ( err != LDAP_SUCCESS )
- {
- LDAPDebug( LDAP_DEBUG_ANY, "seq id2entry err %d\n", err, 0, 0 );
- }
- LDAPDebug( LDAP_DEBUG_ARGS,
- "ldbm_back_seq: candidate %lu not found\n",
- (u_long)id, 0, 0 );
- continue;
- }
- if ( slapi_send_ldap_search_entry( pb, e->ep_entry, NULL, NULL, 0 ) == 0 )
- {
- nentries++;
- }
- cache_return( &inst->inst_cache, &e );
- }
- idl_free( idl );
- }
- dblayer_release_index_file( be, ai, db );
- slapi_send_ldap_result( pb, LDAP_SUCCESS == err ? LDAP_SUCCESS : LDAP_OPERATIONS_ERROR, NULL, NULL, nentries, NULL );
- return 0;
- }
|