Back to index

openldap  2.4.31
delete.c
Go to the documentation of this file.
00001 /* delete.c - bdb backend delete routine */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2000-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 #include <ac/string.h>
00021 
00022 #include "lutil.h"
00023 #include "back-bdb.h"
00024 
00025 int
00026 bdb_delete( Operation *op, SlapReply *rs )
00027 {
00028        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00029        Entry  *matched = NULL;
00030        struct berval pdn = {0, NULL};
00031        Entry  *e = NULL;
00032        Entry  *p = NULL;
00033        EntryInfo     *ei = NULL, *eip = NULL;
00034        int           manageDSAit = get_manageDSAit( op );
00035        AttributeDescription *children = slap_schema.si_ad_children;
00036        AttributeDescription *entry = slap_schema.si_ad_entry;
00037        DB_TXN        *ltid = NULL, *lt2;
00038        struct bdb_op_info opinfo = {{{ 0 }}};
00039        ID     eid;
00040 
00041        DB_LOCK              lock, plock;
00042 
00043        int           num_retries = 0;
00044 
00045        int     rc;
00046 
00047        LDAPControl **preread_ctrl = NULL;
00048        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
00049        int num_ctrls = 0;
00050 
00051        int    parent_is_glue = 0;
00052        int parent_is_leaf = 0;
00053 
00054 #ifdef LDAP_X_TXN
00055        int settle = 0;
00056 #endif
00057 
00058        Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(bdb_delete) ": %s\n",
00059               op->o_req_dn.bv_val, 0, 0 );
00060 
00061 #ifdef LDAP_X_TXN
00062        if( op->o_txnSpec ) {
00063               /* acquire connection lock */
00064               ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00065               if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
00066                      rs->sr_text = "invalid transaction identifier";
00067                      rs->sr_err = LDAP_X_TXN_ID_INVALID;
00068                      goto txnReturn;
00069               } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
00070                      settle=1;
00071                      goto txnReturn;
00072               }
00073 
00074               if( op->o_conn->c_txn_backend == NULL ) {
00075                      op->o_conn->c_txn_backend = op->o_bd;
00076 
00077               } else if( op->o_conn->c_txn_backend != op->o_bd ) {
00078                      rs->sr_text = "transaction cannot span multiple database contexts";
00079                      rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
00080                      goto txnReturn;
00081               }
00082 
00083               /* insert operation into transaction */
00084 
00085               rs->sr_text = "transaction specified";
00086               rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
00087 
00088 txnReturn:
00089               /* release connection lock */
00090               ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00091 
00092               if( !settle ) {
00093                      send_ldap_result( op, rs );
00094                      return rs->sr_err;
00095               }
00096        }
00097 #endif
00098 
00099        ctrls[num_ctrls] = 0;
00100 
00101        /* allocate CSN */
00102        if ( BER_BVISNULL( &op->o_csn ) ) {
00103               struct berval csn;
00104               char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
00105 
00106               csn.bv_val = csnbuf;
00107               csn.bv_len = sizeof(csnbuf);
00108               slap_get_csn( op, &csn, 1 );
00109        }
00110 
00111        if( 0 ) {
00112 retry: /* transaction retry */
00113               if( e != NULL ) {
00114                      bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
00115                      e = NULL;
00116               }
00117               if( p != NULL ) {
00118                      bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
00119                      p = NULL;
00120               }
00121               Debug( LDAP_DEBUG_TRACE,
00122                      "==> " LDAP_XSTRING(bdb_delete) ": retrying...\n",
00123                      0, 0, 0 );
00124               rs->sr_err = TXN_ABORT( ltid );
00125               ltid = NULL;
00126               LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
00127               opinfo.boi_oe.oe_key = NULL;
00128               op->o_do_not_cache = opinfo.boi_acl_cache;
00129               if( rs->sr_err != 0 ) {
00130                      rs->sr_err = LDAP_OTHER;
00131                      rs->sr_text = "internal error";
00132                      goto return_results;
00133               }
00134               if ( op->o_abandon ) {
00135                      rs->sr_err = SLAPD_ABANDON;
00136                      goto return_results;
00137               }
00138               parent_is_glue = 0;
00139               parent_is_leaf = 0;
00140               bdb_trans_backoff( ++num_retries );
00141        }
00142 
00143        /* begin transaction */
00144        rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
00145               bdb->bi_db_opflags );
00146        rs->sr_text = NULL;
00147        if( rs->sr_err != 0 ) {
00148               Debug( LDAP_DEBUG_TRACE,
00149                      LDAP_XSTRING(bdb_delete) ": txn_begin failed: "
00150                      "%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
00151               rs->sr_err = LDAP_OTHER;
00152               rs->sr_text = "internal error";
00153               goto return_results;
00154        }
00155 
00156        opinfo.boi_oe.oe_key = bdb;
00157        opinfo.boi_txn = ltid;
00158        opinfo.boi_err = 0;
00159        opinfo.boi_acl_cache = op->o_do_not_cache;
00160        LDAP_SLIST_INSERT_HEAD( &op->o_extra, &opinfo.boi_oe, oe_next );
00161 
00162        if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
00163               dnParent( &op->o_req_ndn, &pdn );
00164        }
00165 
00166        /* get entry */
00167        rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
00168               &lock );
00169 
00170        switch( rs->sr_err ) {
00171        case 0:
00172        case DB_NOTFOUND:
00173               break;
00174        case DB_LOCK_DEADLOCK:
00175        case DB_LOCK_NOTGRANTED:
00176               goto retry;
00177        case LDAP_BUSY:
00178               rs->sr_text = "ldap server busy";
00179               goto return_results;
00180        default:
00181               rs->sr_err = LDAP_OTHER;
00182               rs->sr_text = "internal error";
00183               goto return_results;
00184        }
00185 
00186        if ( rs->sr_err == 0 ) {
00187               e = ei->bei_e;
00188               eip = ei->bei_parent;
00189        } else {
00190               matched = ei->bei_e;
00191        }
00192 
00193        /* FIXME : dn2entry() should return non-glue entry */
00194        if ( e == NULL || ( !manageDSAit && is_entry_glue( e ))) {
00195               Debug( LDAP_DEBUG_ARGS,
00196                      "<=- " LDAP_XSTRING(bdb_delete) ": no such object %s\n",
00197                      op->o_req_dn.bv_val, 0, 0);
00198 
00199               if ( matched != NULL ) {
00200                      rs->sr_matched = ch_strdup( matched->e_dn );
00201                      rs->sr_ref = is_entry_referral( matched )
00202                             ? get_entry_referrals( op, matched )
00203                             : NULL;
00204                      bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, matched);
00205                      matched = NULL;
00206 
00207               } else {
00208                      rs->sr_ref = referral_rewrite( default_referral, NULL,
00209                                    &op->o_req_dn, LDAP_SCOPE_DEFAULT );
00210               }
00211 
00212               rs->sr_err = LDAP_REFERRAL;
00213               rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
00214               goto return_results;
00215        }
00216 
00217        rc = bdb_cache_find_id( op, ltid, eip->bei_id, &eip, 0, &plock );
00218        switch( rc ) {
00219        case DB_LOCK_DEADLOCK:
00220        case DB_LOCK_NOTGRANTED:
00221               goto retry;
00222        case 0:
00223        case DB_NOTFOUND:
00224               break;
00225        default:
00226               rs->sr_err = LDAP_OTHER;
00227               rs->sr_text = "internal error";
00228               goto return_results;
00229        }
00230        if ( eip ) p = eip->bei_e;
00231 
00232        if ( pdn.bv_len != 0 ) {
00233               if( p == NULL || !bvmatch( &pdn, &p->e_nname )) {
00234                      Debug( LDAP_DEBUG_TRACE,
00235                             "<=- " LDAP_XSTRING(bdb_delete) ": parent "
00236                             "does not exist\n", 0, 0, 0 );
00237                      rs->sr_err = LDAP_OTHER;
00238                      rs->sr_text = "could not locate parent of entry";
00239                      goto return_results;
00240               }
00241 
00242               /* check parent for "children" acl */
00243               rs->sr_err = access_allowed( op, p,
00244                      children, NULL, ACL_WDEL, NULL );
00245 
00246               if ( !rs->sr_err  ) {
00247                      switch( opinfo.boi_err ) {
00248                      case DB_LOCK_DEADLOCK:
00249                      case DB_LOCK_NOTGRANTED:
00250                             goto retry;
00251                      }
00252 
00253                      Debug( LDAP_DEBUG_TRACE,
00254                             "<=- " LDAP_XSTRING(bdb_delete) ": no write "
00255                             "access to parent\n", 0, 0, 0 );
00256                      rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00257                      rs->sr_text = "no write access to parent";
00258                      goto return_results;
00259               }
00260 
00261        } else {
00262               /* no parent, must be root to delete */
00263               if( ! be_isroot( op ) ) {
00264                      if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
00265                             || be_shadow_update( op ) ) {
00266                             p = (Entry *)&slap_entry_root;
00267 
00268                             /* check parent for "children" acl */
00269                             rs->sr_err = access_allowed( op, p,
00270                                    children, NULL, ACL_WDEL, NULL );
00271 
00272                             p = NULL;
00273 
00274                             if ( !rs->sr_err  ) {
00275                                    switch( opinfo.boi_err ) {
00276                                    case DB_LOCK_DEADLOCK:
00277                                    case DB_LOCK_NOTGRANTED:
00278                                           goto retry;
00279                                    }
00280 
00281                                    Debug( LDAP_DEBUG_TRACE,
00282                                           "<=- " LDAP_XSTRING(bdb_delete)
00283                                           ": no access to parent\n",
00284                                           0, 0, 0 );
00285                                    rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00286                                    rs->sr_text = "no write access to parent";
00287                                    goto return_results;
00288                             }
00289 
00290                      } else {
00291                             Debug( LDAP_DEBUG_TRACE,
00292                                    "<=- " LDAP_XSTRING(bdb_delete)
00293                                    ": no parent and not root\n", 0, 0, 0 );
00294                             rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00295                             goto return_results;
00296                      }
00297               }
00298        }
00299 
00300        if ( get_assert( op ) &&
00301               ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
00302        {
00303               rs->sr_err = LDAP_ASSERTION_FAILED;
00304               goto return_results;
00305        }
00306 
00307        rs->sr_err = access_allowed( op, e,
00308               entry, NULL, ACL_WDEL, NULL );
00309 
00310        if ( !rs->sr_err  ) {
00311               switch( opinfo.boi_err ) {
00312               case DB_LOCK_DEADLOCK:
00313               case DB_LOCK_NOTGRANTED:
00314                      goto retry;
00315               }
00316 
00317               Debug( LDAP_DEBUG_TRACE,
00318                      "<=- " LDAP_XSTRING(bdb_delete) ": no write access "
00319                      "to entry\n", 0, 0, 0 );
00320               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00321               rs->sr_text = "no write access to entry";
00322               goto return_results;
00323        }
00324 
00325        if ( !manageDSAit && is_entry_referral( e ) ) {
00326               /* entry is a referral, don't allow delete */
00327               rs->sr_ref = get_entry_referrals( op, e );
00328 
00329               Debug( LDAP_DEBUG_TRACE,
00330                      LDAP_XSTRING(bdb_delete) ": entry is referral\n",
00331                      0, 0, 0 );
00332 
00333               rs->sr_err = LDAP_REFERRAL;
00334               rs->sr_matched = ch_strdup( e->e_name.bv_val );
00335               rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
00336               goto return_results;
00337        }
00338 
00339        /* pre-read */
00340        if( op->o_preread ) {
00341               if( preread_ctrl == NULL ) {
00342                      preread_ctrl = &ctrls[num_ctrls++];
00343                      ctrls[num_ctrls] = NULL;
00344               }
00345               if( slap_read_controls( op, rs, e,
00346                      &slap_pre_read_bv, preread_ctrl ) )
00347               {
00348                      Debug( LDAP_DEBUG_TRACE,
00349                             "<=- " LDAP_XSTRING(bdb_delete) ": pre-read "
00350                             "failed!\n", 0, 0, 0 );
00351                      if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
00352                             /* FIXME: is it correct to abort
00353                              * operation if control fails? */
00354                             goto return_results;
00355                      }
00356               }
00357        }
00358 
00359        /* nested transaction */
00360        rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, 
00361               bdb->bi_db_opflags );
00362        rs->sr_text = NULL;
00363        if( rs->sr_err != 0 ) {
00364               Debug( LDAP_DEBUG_TRACE,
00365                      LDAP_XSTRING(bdb_delete) ": txn_begin(2) failed: "
00366                      "%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
00367               rs->sr_err = LDAP_OTHER;
00368               rs->sr_text = "internal error";
00369               goto return_results;
00370        }
00371 
00372        BDB_LOG_PRINTF( bdb->bi_dbenv, lt2, "slapd Starting delete %s(%d)",
00373               e->e_nname.bv_val, e->e_id );
00374 
00375        /* Can't do it if we have kids */
00376        rs->sr_err = bdb_cache_children( op, lt2, e );
00377        if( rs->sr_err != DB_NOTFOUND ) {
00378               switch( rs->sr_err ) {
00379               case DB_LOCK_DEADLOCK:
00380               case DB_LOCK_NOTGRANTED:
00381                      goto retry;
00382               case 0:
00383                      Debug(LDAP_DEBUG_ARGS,
00384                             "<=- " LDAP_XSTRING(bdb_delete)
00385                             ": non-leaf %s\n",
00386                             op->o_req_dn.bv_val, 0, 0);
00387                      rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
00388                      rs->sr_text = "subordinate objects must be deleted first";
00389                      break;
00390               default:
00391                      Debug(LDAP_DEBUG_ARGS,
00392                             "<=- " LDAP_XSTRING(bdb_delete)
00393                             ": has_children failed: %s (%d)\n",
00394                             db_strerror(rs->sr_err), rs->sr_err, 0 );
00395                      rs->sr_err = LDAP_OTHER;
00396                      rs->sr_text = "internal error";
00397               }
00398               goto return_results;
00399        }
00400 
00401        /* delete from dn2id */
00402        rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e );
00403        if ( rs->sr_err != 0 ) {
00404               Debug(LDAP_DEBUG_TRACE,
00405                      "<=- " LDAP_XSTRING(bdb_delete) ": dn2id failed: "
00406                      "%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
00407               switch( rs->sr_err ) {
00408               case DB_LOCK_DEADLOCK:
00409               case DB_LOCK_NOTGRANTED:
00410                      goto retry;
00411               }
00412               rs->sr_text = "DN index delete failed";
00413               rs->sr_err = LDAP_OTHER;
00414               goto return_results;
00415        }
00416 
00417        /* delete indices for old attributes */
00418        rs->sr_err = bdb_index_entry_del( op, lt2, e );
00419        if ( rs->sr_err != LDAP_SUCCESS ) {
00420               Debug(LDAP_DEBUG_TRACE,
00421                      "<=- " LDAP_XSTRING(bdb_delete) ": index failed: "
00422                      "%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
00423               switch( rs->sr_err ) {
00424               case DB_LOCK_DEADLOCK:
00425               case DB_LOCK_NOTGRANTED:
00426                      goto retry;
00427               }
00428               rs->sr_text = "entry index delete failed";
00429               rs->sr_err = LDAP_OTHER;
00430               goto return_results;
00431        }
00432 
00433        /* fixup delete CSN */
00434        if ( !SLAP_SHADOW( op->o_bd )) {
00435               struct berval vals[2];
00436 
00437               assert( !BER_BVISNULL( &op->o_csn ) );
00438               vals[0] = op->o_csn;
00439               BER_BVZERO( &vals[1] );
00440               rs->sr_err = bdb_index_values( op, lt2, slap_schema.si_ad_entryCSN,
00441                      vals, 0, SLAP_INDEX_ADD_OP );
00442        if ( rs->sr_err != LDAP_SUCCESS ) {
00443                      switch( rs->sr_err ) {
00444                      case DB_LOCK_DEADLOCK:
00445                      case DB_LOCK_NOTGRANTED:
00446                             goto retry;
00447                      }
00448                      rs->sr_text = "entryCSN index update failed";
00449                      rs->sr_err = LDAP_OTHER;
00450                      goto return_results;
00451               }
00452        }
00453 
00454        /* delete from id2entry */
00455        rs->sr_err = bdb_id2entry_delete( op->o_bd, lt2, e );
00456        if ( rs->sr_err != 0 ) {
00457               Debug( LDAP_DEBUG_TRACE,
00458                      "<=- " LDAP_XSTRING(bdb_delete) ": id2entry failed: "
00459                      "%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
00460               switch( rs->sr_err ) {
00461               case DB_LOCK_DEADLOCK:
00462               case DB_LOCK_NOTGRANTED:
00463                      goto retry;
00464               }
00465               rs->sr_text = "entry delete failed";
00466               rs->sr_err = LDAP_OTHER;
00467               goto return_results;
00468        }
00469 
00470        if ( pdn.bv_len != 0 ) {
00471               parent_is_glue = is_entry_glue(p);
00472               rs->sr_err = bdb_cache_children( op, lt2, p );
00473               if ( rs->sr_err != DB_NOTFOUND ) {
00474                      switch( rs->sr_err ) {
00475                      case DB_LOCK_DEADLOCK:
00476                      case DB_LOCK_NOTGRANTED:
00477                             goto retry;
00478                      case 0:
00479                             break;
00480                      default:
00481                             Debug(LDAP_DEBUG_ARGS,
00482                                    "<=- " LDAP_XSTRING(bdb_delete)
00483                                    ": has_children failed: %s (%d)\n",
00484                                    db_strerror(rs->sr_err), rs->sr_err, 0 );
00485                             rs->sr_err = LDAP_OTHER;
00486                             rs->sr_text = "internal error";
00487                             goto return_results;
00488                      }
00489                      parent_is_leaf = 1;
00490               }
00491               bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
00492               p = NULL;
00493        }
00494 
00495        BDB_LOG_PRINTF( bdb->bi_dbenv, lt2, "slapd Commit1 delete %s(%d)",
00496               e->e_nname.bv_val, e->e_id );
00497 
00498        if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
00499               rs->sr_err = LDAP_OTHER;
00500               rs->sr_text = "txn_commit(2) failed";
00501               goto return_results;
00502        }
00503 
00504        eid = e->e_id;
00505 
00506 #if 0  /* Do we want to reclaim deleted IDs? */
00507        ldap_pvt_thread_mutex_lock( &bdb->bi_lastid_mutex );
00508        if ( e->e_id == bdb->bi_lastid ) {
00509               bdb_last_id( op->o_bd, ltid );
00510        }
00511        ldap_pvt_thread_mutex_unlock( &bdb->bi_lastid_mutex );
00512 #endif
00513 
00514        if( op->o_noop ) {
00515               if ( ( rs->sr_err = TXN_ABORT( ltid ) ) != 0 ) {
00516                      rs->sr_text = "txn_abort (no-op) failed";
00517               } else {
00518                      rs->sr_err = LDAP_X_NO_OPERATION;
00519                      ltid = NULL;
00520                      goto return_results;
00521               }
00522        } else {
00523 
00524               BDB_LOG_PRINTF( bdb->bi_dbenv, ltid, "slapd Cache delete %s(%d)",
00525                      e->e_nname.bv_val, e->e_id );
00526 
00527               rc = bdb_cache_delete( bdb, e, ltid, &lock );
00528               switch( rc ) {
00529               case DB_LOCK_DEADLOCK:
00530               case DB_LOCK_NOTGRANTED:
00531                      goto retry;
00532               }
00533 
00534               rs->sr_err = TXN_COMMIT( ltid, 0 );
00535        }
00536        ltid = NULL;
00537        LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
00538        opinfo.boi_oe.oe_key = NULL;
00539 
00540        BDB_LOG_PRINTF( bdb->bi_dbenv, NULL, "slapd Committed delete %s(%d)",
00541               e->e_nname.bv_val, e->e_id );
00542 
00543        if( rs->sr_err != 0 ) {
00544               Debug( LDAP_DEBUG_TRACE,
00545                      LDAP_XSTRING(bdb_delete) ": txn_%s failed: %s (%d)\n",
00546                      op->o_noop ? "abort (no-op)" : "commit",
00547                      db_strerror(rs->sr_err), rs->sr_err );
00548               rs->sr_err = LDAP_OTHER;
00549               rs->sr_text = "commit failed";
00550 
00551               goto return_results;
00552        }
00553 
00554        Debug( LDAP_DEBUG_TRACE,
00555               LDAP_XSTRING(bdb_delete) ": deleted%s id=%08lx dn=\"%s\"\n",
00556               op->o_noop ? " (no-op)" : "",
00557               eid, op->o_req_dn.bv_val );
00558        rs->sr_err = LDAP_SUCCESS;
00559        rs->sr_text = NULL;
00560        if( num_ctrls ) rs->sr_ctrls = ctrls;
00561 
00562 return_results:
00563        if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
00564               op->o_delete_glue_parent = 1;
00565        }
00566 
00567        if ( p )
00568               bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
00569 
00570        /* free entry */
00571        if( e != NULL ) {
00572               if ( rs->sr_err == LDAP_SUCCESS ) {
00573                      /* Free the EntryInfo and the Entry */
00574                      bdb_cache_entryinfo_lock( BEI(e) );
00575                      bdb_cache_delete_cleanup( &bdb->bi_cache, BEI(e) );
00576               } else {
00577                      bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
00578               }
00579        }
00580 
00581        if( ltid != NULL ) {
00582               TXN_ABORT( ltid );
00583        }
00584        if ( opinfo.boi_oe.oe_key ) {
00585               LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
00586        }
00587 
00588        send_ldap_result( op, rs );
00589        slap_graduate_commit_csn( op );
00590 
00591        if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
00592               slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
00593               slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
00594        }
00595 
00596        if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp_kbyte ) {
00597               TXN_CHECKPOINT( bdb->bi_dbenv,
00598                      bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
00599        }
00600        return rs->sr_err;
00601 }