]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/delete.c
ITS#3309 better fix, add op->ord_csn in frontend and use it in backend.
[openldap] / servers / slapd / back-bdb / delete.c
1 /* delete.c - bdb backend delete routine */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21
22 #include "back-bdb.h"
23 #include "external.h"
24
25 int
26 bdb_delete( Operation *op, SlapReply *rs )
27 {
28         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
29         Entry   *matched = NULL;
30         struct berval   pdn = {0, NULL};
31         Entry   *e = NULL;
32         Entry   *p = NULL;
33         EntryInfo       *ei = NULL, *eip = NULL;
34         int             manageDSAit = get_manageDSAit( op );
35         AttributeDescription *children = slap_schema.si_ad_children;
36         AttributeDescription *entry = slap_schema.si_ad_entry;
37         DB_TXN          *ltid = NULL, *lt2;
38         struct bdb_op_info opinfo;
39
40         u_int32_t       locker = 0;
41         DB_LOCK         lock, plock;
42
43         int             num_retries = 0;
44
45         Operation* ps_list;
46         int     rc;
47         EntryInfo   *suffix_ei;
48         Entry       *ctxcsn_e;
49         int         ctxcsn_added = 0;
50
51         LDAPControl **preread_ctrl = NULL;
52         LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
53         int num_ctrls = 0;
54
55         int     parent_is_glue = 0;
56         int parent_is_leaf = 0;
57
58         ctrls[num_ctrls] = 0;
59
60 #ifdef NEW_LOGGING
61         LDAP_LOG ( OPERATION, ARGS, "==> bdb_delete: %s\n",
62                 op->o_req_dn.bv_val, 0, 0 );
63 #else
64         Debug( LDAP_DEBUG_ARGS, "==> bdb_delete: %s\n",
65                 op->o_req_dn.bv_val, 0, 0 );
66 #endif
67
68         if( 0 ) {
69 retry:  /* transaction retry */
70                 if( e != NULL ) {
71                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
72                         e = NULL;
73                 }
74                 if( p != NULL ) {
75                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
76                         p = NULL;
77                 }
78 #ifdef NEW_LOGGING
79                 LDAP_LOG ( OPERATION, DETAIL1, 
80                         "==> bdb_delete: retrying...\n", 0, 0, 0 );
81 #else
82                 Debug( LDAP_DEBUG_TRACE, "==> bdb_delete: retrying...\n",
83                         0, 0, 0 );
84 #endif
85                 rs->sr_err = TXN_ABORT( ltid );
86                 ltid = NULL;
87                 op->o_private = NULL;
88                 op->o_do_not_cache = opinfo.boi_acl_cache;
89                 if( rs->sr_err != 0 ) {
90                         rs->sr_err = LDAP_OTHER;
91                         rs->sr_text = "internal error";
92                         goto return_results;
93                 }
94                 parent_is_glue = 0;
95                 parent_is_leaf = 0;
96                 ldap_pvt_thread_yield();
97                 bdb_trans_backoff( ++num_retries );
98         }
99
100         /* begin transaction */
101         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
102                 bdb->bi_db_opflags );
103         rs->sr_text = NULL;
104         if( rs->sr_err != 0 ) {
105 #ifdef NEW_LOGGING
106                 LDAP_LOG ( OPERATION, ERR, 
107                         "==> bdb_delete: txn_begin failed: %s (%d)\n",
108                         db_strerror(rs->sr_err), rs->sr_err, 0 );
109 #else
110                 Debug( LDAP_DEBUG_TRACE,
111                         "bdb_delete: txn_begin failed: %s (%d)\n",
112                         db_strerror(rs->sr_err), rs->sr_err, 0 );
113 #endif
114                 rs->sr_err = LDAP_OTHER;
115                 rs->sr_text = "internal error";
116                 goto return_results;
117         }
118
119         locker = TXN_ID ( ltid );
120
121         opinfo.boi_bdb = op->o_bd;
122         opinfo.boi_txn = ltid;
123         opinfo.boi_locker = locker;
124         opinfo.boi_err = 0;
125         opinfo.boi_acl_cache = op->o_do_not_cache;
126         op->o_private = &opinfo;
127
128         if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
129                 dnParent( &op->o_req_ndn, &pdn );
130         }
131
132         /* get entry */
133         rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
134                 locker, &lock );
135
136         switch( rs->sr_err ) {
137         case 0:
138         case DB_NOTFOUND:
139                 break;
140         case DB_LOCK_DEADLOCK:
141         case DB_LOCK_NOTGRANTED:
142                 goto retry;
143         case LDAP_BUSY:
144                 rs->sr_text = "ldap server busy";
145                 goto return_results;
146         default:
147                 rs->sr_err = LDAP_OTHER;
148                 rs->sr_text = "internal error";
149                 goto return_results;
150         }
151
152         if ( rs->sr_err == 0 ) {
153                 e = ei->bei_e;
154                 eip = ei->bei_parent;
155         } else {
156                 matched = ei->bei_e;
157         }
158
159         /* FIXME : dn2entry() should return non-glue entry */
160         if ( e == NULL || ( !manageDSAit && is_entry_glue( e ))) {
161 #ifdef NEW_LOGGING
162                 LDAP_LOG ( OPERATION, ARGS, 
163                         "<=- bdb_delete: no such object %s\n", op->o_req_dn.bv_val, 0, 0);
164 #else
165                 Debug( LDAP_DEBUG_ARGS,
166                         "<=- bdb_delete: no such object %s\n",
167                         op->o_req_dn.bv_val, 0, 0);
168 #endif
169
170                 if ( matched != NULL ) {
171                         rs->sr_matched = ch_strdup( matched->e_dn );
172                         rs->sr_ref = is_entry_referral( matched )
173                                 ? get_entry_referrals( op, matched )
174                                 : NULL;
175                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, matched);
176                         matched = NULL;
177
178                 } else {
179                         BerVarray deref = NULL;
180                         if ( !LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
181                                 syncinfo_t *si;
182                                 LDAP_STAILQ_FOREACH( si, &op->o_bd->be_syncinfo, si_next ) {
183                                         struct berval tmpbv;
184                                         ber_dupbv( &tmpbv, &si->si_provideruri_bv[0] );
185                                         ber_bvarray_add( &deref, &tmpbv );
186                                 }
187                         } else {
188                                 deref = default_referral;
189                         }
190                         rs->sr_ref = referral_rewrite( deref, NULL, &op->o_req_dn,
191                                 LDAP_SCOPE_DEFAULT );
192                 }
193
194                 rs->sr_err = LDAP_REFERRAL;
195                 send_ldap_result( op, rs );
196
197                 if ( rs->sr_ref != default_referral ) {
198                         ber_bvarray_free( rs->sr_ref );
199                 }
200                 free( (char *)rs->sr_matched );
201                 rs->sr_ref = NULL;
202                 rs->sr_matched = NULL;
203
204                 rs->sr_err = -1;
205                 goto done;
206         }
207
208         rc = bdb_cache_find_id( op, ltid, eip->bei_id, &eip, 0, locker, &plock );
209         switch( rc ) {
210         case DB_LOCK_DEADLOCK:
211         case DB_LOCK_NOTGRANTED:
212                 goto retry;
213         case 0:
214         case DB_NOTFOUND:
215                 break;
216         default:
217                 rs->sr_err = LDAP_OTHER;
218                 rs->sr_text = "internal error";
219                 goto return_results;
220         }
221         if ( eip ) p = eip->bei_e;
222
223         if ( pdn.bv_len != 0 ) {
224                 if( p == NULL || !bvmatch( &pdn, &p->e_nname )) {
225 #ifdef NEW_LOGGING
226                         LDAP_LOG ( OPERATION, DETAIL1, 
227                                 "<=- bdb_delete: parent does not exist\n", 0, 0, 0 );
228 #else
229                         Debug( LDAP_DEBUG_TRACE,
230                                 "<=- bdb_delete: parent does not exist\n",
231                                 0, 0, 0);
232 #endif
233                         rs->sr_err = LDAP_OTHER;
234                         rs->sr_text = "could not locate parent of entry";
235                         goto return_results;
236                 }
237
238                 /* check parent for "children" acl */
239                 rs->sr_err = access_allowed( op, p,
240                         children, NULL, ACL_WRITE, NULL );
241
242                 if ( !rs->sr_err  ) {
243                         switch( opinfo.boi_err ) {
244                         case DB_LOCK_DEADLOCK:
245                         case DB_LOCK_NOTGRANTED:
246                                 goto retry;
247                         }
248
249 #ifdef NEW_LOGGING
250                         LDAP_LOG ( OPERATION, DETAIL1, 
251                                 "<=- bdb_delete: no write access to parent\n", 0, 0, 0 );
252 #else
253                         Debug( LDAP_DEBUG_TRACE,
254                                 "<=- bdb_delete: no write access to parent\n",
255                                 0, 0, 0 );
256 #endif
257                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
258                         rs->sr_text = "no write access to parent";
259                         goto return_results;
260                 }
261
262         } else {
263                 /* no parent, must be root to delete */
264                 if( ! be_isroot( op ) ) {
265                         if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
266                                 || be_shadow_update( op ) ) {
267                                 p = (Entry *)&slap_entry_root;
268
269                                 /* check parent for "children" acl */
270                                 rs->sr_err = access_allowed( op, p,
271                                         children, NULL, ACL_WRITE, NULL );
272
273                                 p = NULL;
274
275                                 if ( !rs->sr_err  ) {
276                                         switch( opinfo.boi_err ) {
277                                         case DB_LOCK_DEADLOCK:
278                                         case DB_LOCK_NOTGRANTED:
279                                                 goto retry;
280                                         }
281
282 #ifdef NEW_LOGGING
283                                         LDAP_LOG ( OPERATION, DETAIL1, 
284                                                 "<=- bdb_delete: no access to parent\n", 0, 0, 0 );
285 #else
286                                         Debug( LDAP_DEBUG_TRACE,
287                                                 "<=- bdb_delete: no access "
288                                                 "to parent\n", 0, 0, 0 );
289 #endif
290                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
291                                         rs->sr_text = "no write access to parent";
292                                         goto return_results;
293                                 }
294
295                         } else {
296 #ifdef NEW_LOGGING
297                                 LDAP_LOG ( OPERATION, DETAIL1, 
298                                         "<=- bdb_delete: no parent and not root\n", 0, 0, 0 );
299 #else
300                                 Debug( LDAP_DEBUG_TRACE,
301                                         "<=- bdb_delete: no parent "
302                                         "and not root\n", 0, 0, 0);
303 #endif
304                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
305                                 goto return_results;
306                         }
307                 }
308         }
309
310         if ( get_assert( op ) &&
311                 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
312         {
313                 rs->sr_err = LDAP_ASSERTION_FAILED;
314                 goto return_results;
315         }
316
317         rs->sr_err = access_allowed( op, e,
318                 entry, NULL, ACL_WRITE, NULL );
319
320         if ( !rs->sr_err  ) {
321                 switch( opinfo.boi_err ) {
322                 case DB_LOCK_DEADLOCK:
323                 case DB_LOCK_NOTGRANTED:
324                         goto retry;
325                 }
326
327 #ifdef NEW_LOGGING
328                 LDAP_LOG ( OPERATION, DETAIL1, 
329                         "<=- bdb_delete: no write access to entry\n", 0, 0, 0 );
330 #else
331                 Debug( LDAP_DEBUG_TRACE,
332                         "<=- bdb_delete: no write access to entry\n",
333                         0, 0, 0 );
334 #endif
335                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
336                 rs->sr_text = "no write access to entry";
337                 goto return_results;
338         }
339
340         if ( !manageDSAit && is_entry_referral( e ) ) {
341                 /* entry is a referral, don't allow delete */
342                 rs->sr_ref = get_entry_referrals( op, e );
343
344 #ifdef NEW_LOGGING
345                 LDAP_LOG ( OPERATION, DETAIL1, 
346                         "<=- bdb_delete: entry is referral\n", 0, 0, 0 );
347 #else
348                 Debug( LDAP_DEBUG_TRACE,
349                         "bdb_delete: entry is referral\n", 0, 0, 0 );
350 #endif
351
352                 rs->sr_err = LDAP_REFERRAL;
353                 rs->sr_matched = e->e_name.bv_val;
354                 send_ldap_result( op, rs );
355
356                 ber_bvarray_free( rs->sr_ref );
357                 rs->sr_ref = NULL;
358                 rs->sr_matched = NULL;
359
360                 rs->sr_err = 1;
361                 goto done;
362         }
363
364         /* pre-read */
365         if( op->o_preread ) {
366                 if( preread_ctrl == NULL ) {
367                         preread_ctrl = &ctrls[num_ctrls++];
368                         ctrls[num_ctrls] = NULL;
369                 }
370                 if( slap_read_controls( op, rs, e,
371                         &slap_pre_read_bv, preread_ctrl ) )
372                 {
373 #ifdef NEW_LOGGING
374                         LDAP_LOG ( OPERATION, DETAIL1, 
375                                 "<=- bdb_delete: pre-read failed!\n", 0, 0, 0 );
376 #else
377                         Debug( LDAP_DEBUG_TRACE,
378                                 "<=- bdb_delete: pre-read failed!\n", 0, 0, 0 );
379 #endif
380                         goto return_results;
381                 }
382         }
383
384         /* nested transaction */
385         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, 
386                 bdb->bi_db_opflags );
387         rs->sr_text = NULL;
388         if( rs->sr_err != 0 ) {
389 #ifdef NEW_LOGGING
390                 LDAP_LOG ( OPERATION, ERR, 
391                         "bdb_delete: txn_begin(2) failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
392 #else
393                 Debug( LDAP_DEBUG_TRACE,
394                         "bdb_delete: txn_begin(2) failed: %s (%d)\n",
395                         db_strerror(rs->sr_err), rs->sr_err, 0 );
396 #endif
397                 rs->sr_err = LDAP_OTHER;
398                 rs->sr_text = "internal error";
399                 goto return_results;
400         }
401
402         /* Can't do it if we have kids */
403         rs->sr_err = bdb_cache_children( op, lt2, e );
404         if( rs->sr_err != DB_NOTFOUND ) {
405                 switch( rs->sr_err ) {
406                 case DB_LOCK_DEADLOCK:
407                 case DB_LOCK_NOTGRANTED:
408                         goto retry;
409                 case 0:
410 #ifdef NEW_LOGGING
411                         LDAP_LOG ( OPERATION, DETAIL1, 
412                                 "<=- bdb_delete: non-leaf %s\n", op->o_req_dn.bv_val, 0, 0 );
413 #else
414                         Debug(LDAP_DEBUG_ARGS,
415                                 "<=- bdb_delete: non-leaf %s\n",
416                                 op->o_req_dn.bv_val, 0, 0);
417 #endif
418                         rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
419                         rs->sr_text = "subtree delete not supported";
420                         break;
421                 default:
422 #ifdef NEW_LOGGING
423                         LDAP_LOG ( OPERATION, ERR, 
424                                 "<=- bdb_delete: has_children failed %s (%d)\n",
425                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
426 #else
427                         Debug(LDAP_DEBUG_ARGS,
428                                 "<=- bdb_delete: has_children failed: %s (%d)\n",
429                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
430 #endif
431                         rs->sr_err = LDAP_OTHER;
432                         rs->sr_text = "internal error";
433                 }
434                 goto return_results;
435         }
436
437         /* delete from dn2id */
438         rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e );
439         if ( rs->sr_err != 0 ) {
440 #ifdef NEW_LOGGING
441                 LDAP_LOG ( OPERATION, ERR, 
442                         "<=- bdb_delete: dn2id failed: %s (%d)\n",
443                         db_strerror(rs->sr_err), rs->sr_err, 0 );
444 #else
445                 Debug(LDAP_DEBUG_TRACE,
446                         "<=- bdb_delete: dn2id failed: %s (%d)\n",
447                         db_strerror(rs->sr_err), rs->sr_err, 0 );
448 #endif
449                 switch( rs->sr_err ) {
450                 case DB_LOCK_DEADLOCK:
451                 case DB_LOCK_NOTGRANTED:
452                         goto retry;
453                 }
454                 rs->sr_text = "DN index delete failed";
455                 rs->sr_err = LDAP_OTHER;
456                 goto return_results;
457         }
458
459         /* delete from id2entry */
460         rs->sr_err = bdb_id2entry_delete( op->o_bd, lt2, e );
461         if ( rs->sr_err != 0 ) {
462 #ifdef NEW_LOGGING
463                 LDAP_LOG ( OPERATION, ERR, 
464                         "<=- bdb_delete: id2entry failed: %s (%d)\n", 
465                         db_strerror(rs->sr_err), rs->sr_err, 0 );
466 #else
467                 Debug(LDAP_DEBUG_TRACE,
468                         "<=- bdb_delete: id2entry failed: %s (%d)\n",
469                         db_strerror(rs->sr_err), rs->sr_err, 0 );
470 #endif
471                 switch( rs->sr_err ) {
472                 case DB_LOCK_DEADLOCK:
473                 case DB_LOCK_NOTGRANTED:
474                         goto retry;
475                 }
476                 rs->sr_text = "entry delete failed";
477                 rs->sr_err = LDAP_OTHER;
478                 goto return_results;
479         }
480
481         /* delete indices for old attributes */
482         rs->sr_err = bdb_index_entry_del( op, lt2, e );
483         if ( rs->sr_err != LDAP_SUCCESS ) {
484 #ifdef NEW_LOGGING
485                 LDAP_LOG ( OPERATION, ERR, 
486                         "<=- bdb_delete: index failed: %s (%d)\n", 
487                         db_strerror(rs->sr_err), rs->sr_err, 0 );
488 #else
489                 Debug( LDAP_DEBUG_TRACE,
490                         "<=- bdb_delete: index failed: %s (%d)\n", 
491                         db_strerror(rs->sr_err), rs->sr_err, 0 );
492 #endif
493                 switch( rs->sr_err ) {
494                 case DB_LOCK_DEADLOCK:
495                 case DB_LOCK_NOTGRANTED:
496                         goto retry;
497                 }
498                 rs->sr_text = "entry index delete failed";
499                 rs->sr_err = LDAP_OTHER;
500                 goto return_results;
501         }
502
503         if ( pdn.bv_len != 0 ) {
504                 parent_is_glue = is_entry_glue(p);
505                 rs->sr_err = bdb_cache_children( op, lt2, p );
506                 if ( rs->sr_err != DB_NOTFOUND ) {
507                         switch( rs->sr_err ) {
508                         case DB_LOCK_DEADLOCK:
509                         case DB_LOCK_NOTGRANTED:
510                                 goto retry;
511                         case 0:
512                                 break;
513                         default:
514 #ifdef NEW_LOGGING
515                                 LDAP_LOG ( OPERATION, ERR, 
516                                         "<=- bdb_delete: has_children failed %s (%d)\n",
517                                         db_strerror(rs->sr_err), rs->sr_err, 0 );
518 #else
519                                 Debug(LDAP_DEBUG_ARGS,
520                                         "<=- bdb_delete: has_children failed: %s (%d)\n",
521                                         db_strerror(rs->sr_err), rs->sr_err, 0 );
522 #endif
523                                 rs->sr_err = LDAP_OTHER;
524                                 rs->sr_text = "internal error";
525                                 goto return_results;
526                         }
527                         parent_is_leaf = 1;
528                 }
529                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
530                 p = NULL;
531         }
532
533         if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
534                 rs->sr_err = LDAP_OTHER;
535                 rs->sr_text = "txn_commit(2) failed";
536                 goto return_results;
537         }
538
539 #if 0   /* Do we want to reclaim deleted IDs? */
540         ldap_pvt_thread_mutex_lock( &bdb->bi_lastid_mutex );
541         if ( e->e_id == bdb->bi_lastid ) {
542                 bdb_last_id( op->o_bd, ltid );
543         }
544         ldap_pvt_thread_mutex_unlock( &bdb->bi_lastid_mutex );
545 #endif
546
547         if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
548                 rc = bdb_csn_commit( op, rs, ltid, ei, &suffix_ei,
549                         &ctxcsn_e, &ctxcsn_added, locker );
550                 switch ( rc ) {
551                 case BDB_CSN_ABORT :
552                         goto return_results;
553                 case BDB_CSN_RETRY :
554                         goto retry;
555                 }
556         }
557
558         if( op->o_noop ) {
559                 if ( ( rs->sr_err = TXN_ABORT( ltid ) ) != 0 ) {
560                         rs->sr_text = "txn_abort (no-op) failed";
561                 } else {
562                         rs->sr_err = LDAP_NO_OPERATION;
563                         goto return_results;
564                 }
565         } else {
566                 rc = bdb_cache_delete( &bdb->bi_cache, e, bdb->bi_dbenv,
567                         locker, &lock );
568                 switch( rc ) {
569                 case DB_LOCK_DEADLOCK:
570                 case DB_LOCK_NOTGRANTED:
571                         goto retry;
572                 }
573
574                 if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
575                         if ( ctxcsn_added ) {
576                                 bdb_cache_add( bdb, suffix_ei,
577                                         ctxcsn_e, (struct berval *)&slap_ldapsync_cn_bv, locker );
578                         }
579                 }
580
581                 if ( rs->sr_err == LDAP_SUCCESS && !op->o_no_psearch ) {
582                         Attribute *a;
583                         a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
584                         if ( a ) {
585                                 if( (void *) e->e_attrs != (void *) (e+1)) {
586                                         attr_delete( &e->e_attrs, slap_schema.si_ad_entryCSN );
587                                         attr_merge_normalize_one( e, slap_schema.si_ad_entryCSN,
588                                         &op->ord_csn, NULL );
589                                 } else {
590                                         a->a_vals[0] = op->ord_csn;
591                                 }
592                         } else {
593                                 /* Hm, the entryCSN ought to exist. ??? */
594                         }
595                         ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock );
596                         LDAP_LIST_FOREACH( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
597                                 rc = bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_DELETE );
598                                 if ( rc ) {
599 #ifdef NEW_LOGGING
600                                         LDAP_LOG ( OPERATION, ERR,
601                                                 "bdb_delete: persistent search failed (%d,%d)\n",
602                                                 rc, rs->sr_err, 0 );
603 #else
604                                         Debug( LDAP_DEBUG_TRACE,
605                                                 "bdb_delete: persistent search failed (%d,%d)\n",
606                                                 rc, rs->sr_err, 0 );
607 #endif
608                                 }
609                         }
610                         ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock );
611                 }
612
613                 rs->sr_err = TXN_COMMIT( ltid, 0 );
614         }
615         ltid = NULL;
616         op->o_private = NULL;
617
618         if( rs->sr_err != 0 ) {
619 #ifdef NEW_LOGGING
620                 LDAP_LOG ( OPERATION, ERR, 
621                         "bdb_delete: txn_%s failed: %s (%d)\n",
622                         op->o_noop ? "abort (no-op)" : "commit",
623                         db_strerror(rs->sr_err), rs->sr_err );
624 #else
625                 Debug( LDAP_DEBUG_TRACE,
626                         "bdb_delete: txn_%s failed: %s (%d)\n",
627                         op->o_noop ? "abort (no-op)" : "commit",
628                         db_strerror(rs->sr_err), rs->sr_err );
629 #endif
630                 rs->sr_err = LDAP_OTHER;
631                 rs->sr_text = "commit failed";
632
633                 goto return_results;
634         }
635
636 #ifdef NEW_LOGGING
637         LDAP_LOG ( OPERATION, RESULTS, 
638                 "bdb_delete: deleted%s id=%08lx db=\"%s\"\n",
639                 op->o_noop ? " (no-op)" : "",
640                 e->e_id, e->e_dn );
641 #else
642         Debug( LDAP_DEBUG_TRACE,
643                 "bdb_delete: deleted%s id=%08lx dn=\"%s\"\n",
644                 op->o_noop ? " (no-op)" : "",
645                 e->e_id, e->e_dn );
646 #endif
647         rs->sr_err = LDAP_SUCCESS;
648         rs->sr_text = NULL;
649         if( num_ctrls ) rs->sr_ctrls = ctrls;
650
651 return_results:
652         send_ldap_result( op, rs );
653
654         if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) {
655                 ldap_pvt_thread_yield();
656                 TXN_CHECKPOINT( bdb->bi_dbenv,
657                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
658         }
659
660         if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
661                 op->o_delete_glue_parent = 1;
662         }
663
664 done:
665         if ( p )
666                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
667
668         /* free entry */
669         if( e != NULL ) {
670                 if ( rs->sr_err == LDAP_SUCCESS ) {
671                         /* Free the EntryInfo and the Entry */
672                         bdb_cache_delete_cleanup( &bdb->bi_cache, e );
673                 } else {
674                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
675                 }
676         }
677
678         if( ltid != NULL ) {
679                 TXN_ABORT( ltid );
680                 op->o_private = NULL;
681         }
682
683         if( preread_ctrl != NULL ) {
684                 slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, &op->o_tmpmemctx );
685                 slap_sl_free( *preread_ctrl, &op->o_tmpmemctx );
686         }
687         return rs->sr_err;
688 }