]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/delete.c
More locking cleanup (ITS#3201, etc)
[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         if ( rc ) {
210                 switch( rc ) {
211                 case DB_LOCK_DEADLOCK:
212                 case DB_LOCK_NOTGRANTED:
213                         goto retry;
214                 }
215                 rs->sr_err = LDAP_OTHER;
216                 rs->sr_text = "internal error";
217                 goto return_results;
218         }
219         if ( eip ) p = eip->bei_e;
220
221         if ( pdn.bv_len != 0 ) {
222                 if( p == NULL || !bvmatch( &pdn, &p->e_nname )) {
223 #ifdef NEW_LOGGING
224                         LDAP_LOG ( OPERATION, DETAIL1, 
225                                 "<=- bdb_delete: parent does not exist\n", 0, 0, 0 );
226 #else
227                         Debug( LDAP_DEBUG_TRACE,
228                                 "<=- bdb_delete: parent does not exist\n",
229                                 0, 0, 0);
230 #endif
231                         rs->sr_err = LDAP_OTHER;
232                         rs->sr_text = "could not locate parent of entry";
233                         goto return_results;
234                 }
235
236                 /* check parent for "children" acl */
237                 rs->sr_err = access_allowed( op, p,
238                         children, NULL, ACL_WRITE, NULL );
239
240                 if ( !rs->sr_err  ) {
241                         switch( opinfo.boi_err ) {
242                         case DB_LOCK_DEADLOCK:
243                         case DB_LOCK_NOTGRANTED:
244                                 goto retry;
245                         }
246
247 #ifdef NEW_LOGGING
248                         LDAP_LOG ( OPERATION, DETAIL1, 
249                                 "<=- bdb_delete: no write access to parent\n", 0, 0, 0 );
250 #else
251                         Debug( LDAP_DEBUG_TRACE,
252                                 "<=- bdb_delete: no write access to parent\n",
253                                 0, 0, 0 );
254 #endif
255                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
256                         rs->sr_text = "no write access to parent";
257                         goto return_results;
258                 }
259
260         } else {
261                 /* no parent, must be root to delete */
262                 if( ! be_isroot( op ) ) {
263                         if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
264                                 || be_shadow_update( op ) ) {
265                                 p = (Entry *)&slap_entry_root;
266
267                                 /* check parent for "children" acl */
268                                 rs->sr_err = access_allowed( op, p,
269                                         children, NULL, ACL_WRITE, NULL );
270
271                                 p = NULL;
272
273                                 if ( !rs->sr_err  ) {
274                                         switch( opinfo.boi_err ) {
275                                         case DB_LOCK_DEADLOCK:
276                                         case DB_LOCK_NOTGRANTED:
277                                                 goto retry;
278                                         }
279
280 #ifdef NEW_LOGGING
281                                         LDAP_LOG ( OPERATION, DETAIL1, 
282                                                 "<=- bdb_delete: no access to parent\n", 0, 0, 0 );
283 #else
284                                         Debug( LDAP_DEBUG_TRACE,
285                                                 "<=- bdb_delete: no access "
286                                                 "to parent\n", 0, 0, 0 );
287 #endif
288                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
289                                         rs->sr_text = "no write access to parent";
290                                         goto return_results;
291                                 }
292
293                         } else {
294 #ifdef NEW_LOGGING
295                                 LDAP_LOG ( OPERATION, DETAIL1, 
296                                         "<=- bdb_delete: no parent and not root\n", 0, 0, 0 );
297 #else
298                                 Debug( LDAP_DEBUG_TRACE,
299                                         "<=- bdb_delete: no parent "
300                                         "and not root\n", 0, 0, 0);
301 #endif
302                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
303                                 goto return_results;
304                         }
305                 }
306         }
307
308         if ( get_assert( op ) &&
309                 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
310         {
311                 rs->sr_err = LDAP_ASSERTION_FAILED;
312                 goto return_results;
313         }
314
315         rs->sr_err = access_allowed( op, e,
316                 entry, NULL, ACL_WRITE, NULL );
317
318         if ( !rs->sr_err  ) {
319                 switch( opinfo.boi_err ) {
320                 case DB_LOCK_DEADLOCK:
321                 case DB_LOCK_NOTGRANTED:
322                         goto retry;
323                 }
324
325 #ifdef NEW_LOGGING
326                 LDAP_LOG ( OPERATION, DETAIL1, 
327                         "<=- bdb_delete: no write access to entry\n", 0, 0, 0 );
328 #else
329                 Debug( LDAP_DEBUG_TRACE,
330                         "<=- bdb_delete: no write access to entry\n",
331                         0, 0, 0 );
332 #endif
333                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
334                 rs->sr_text = "no write access to entry";
335                 goto return_results;
336         }
337
338         if ( !manageDSAit && is_entry_referral( e ) ) {
339                 /* entry is a referral, don't allow delete */
340                 rs->sr_ref = get_entry_referrals( op, e );
341
342 #ifdef NEW_LOGGING
343                 LDAP_LOG ( OPERATION, DETAIL1, 
344                         "<=- bdb_delete: entry is referral\n", 0, 0, 0 );
345 #else
346                 Debug( LDAP_DEBUG_TRACE,
347                         "bdb_delete: entry is referral\n", 0, 0, 0 );
348 #endif
349
350                 rs->sr_err = LDAP_REFERRAL;
351                 rs->sr_matched = e->e_name.bv_val;
352                 send_ldap_result( op, rs );
353
354                 ber_bvarray_free( rs->sr_ref );
355                 rs->sr_ref = NULL;
356                 rs->sr_matched = NULL;
357
358                 rs->sr_err = 1;
359                 goto done;
360         }
361
362         /* pre-read */
363         if( op->o_preread ) {
364                 if( preread_ctrl == NULL ) {
365                         preread_ctrl = &ctrls[num_ctrls++];
366                         ctrls[num_ctrls] = NULL;
367                 }
368                 if( slap_read_controls( op, rs, e,
369                         &slap_pre_read_bv, preread_ctrl ) )
370                 {
371 #ifdef NEW_LOGGING
372                         LDAP_LOG ( OPERATION, DETAIL1, 
373                                 "<=- bdb_delete: pre-read failed!\n", 0, 0, 0 );
374 #else
375                         Debug( LDAP_DEBUG_TRACE,
376                                 "<=- bdb_delete: pre-read failed!\n", 0, 0, 0 );
377 #endif
378                         goto return_results;
379                 }
380         }
381
382         /* nested transaction */
383         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, 
384                 bdb->bi_db_opflags );
385         rs->sr_text = NULL;
386         if( rs->sr_err != 0 ) {
387 #ifdef NEW_LOGGING
388                 LDAP_LOG ( OPERATION, ERR, 
389                         "bdb_delete: txn_begin(2) failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
390 #else
391                 Debug( LDAP_DEBUG_TRACE,
392                         "bdb_delete: txn_begin(2) failed: %s (%d)\n",
393                         db_strerror(rs->sr_err), rs->sr_err, 0 );
394 #endif
395                 rs->sr_err = LDAP_OTHER;
396                 rs->sr_text = "internal error";
397                 goto return_results;
398         }
399
400         /* Can't do it if we have kids */
401         rs->sr_err = bdb_cache_children( op, lt2, e );
402         if( rs->sr_err != DB_NOTFOUND ) {
403                 switch( rs->sr_err ) {
404                 case DB_LOCK_DEADLOCK:
405                 case DB_LOCK_NOTGRANTED:
406                         goto retry;
407                 case 0:
408 #ifdef NEW_LOGGING
409                         LDAP_LOG ( OPERATION, DETAIL1, 
410                                 "<=- bdb_delete: non-leaf %s\n", op->o_req_dn.bv_val, 0, 0 );
411 #else
412                         Debug(LDAP_DEBUG_ARGS,
413                                 "<=- bdb_delete: non-leaf %s\n",
414                                 op->o_req_dn.bv_val, 0, 0);
415 #endif
416                         rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
417                         rs->sr_text = "subtree delete not supported";
418                         break;
419                 default:
420 #ifdef NEW_LOGGING
421                         LDAP_LOG ( OPERATION, ERR, 
422                                 "<=- bdb_delete: has_children failed %s (%d)\n",
423                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
424 #else
425                         Debug(LDAP_DEBUG_ARGS,
426                                 "<=- bdb_delete: has_children failed: %s (%d)\n",
427                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
428 #endif
429                         rs->sr_err = LDAP_OTHER;
430                         rs->sr_text = "internal error";
431                 }
432                 goto return_results;
433         }
434
435         /* delete from dn2id */
436         rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e );
437         if ( rs->sr_err != 0 ) {
438 #ifdef NEW_LOGGING
439                 LDAP_LOG ( OPERATION, ERR, 
440                         "<=- bdb_delete: dn2id failed: %s (%d)\n",
441                         db_strerror(rs->sr_err), rs->sr_err, 0 );
442 #else
443                 Debug(LDAP_DEBUG_TRACE,
444                         "<=- bdb_delete: dn2id failed: %s (%d)\n",
445                         db_strerror(rs->sr_err), rs->sr_err, 0 );
446 #endif
447                 switch( rs->sr_err ) {
448                 case DB_LOCK_DEADLOCK:
449                 case DB_LOCK_NOTGRANTED:
450                         goto retry;
451                 }
452                 rs->sr_text = "DN index delete failed";
453                 rs->sr_err = LDAP_OTHER;
454                 goto return_results;
455         }
456
457         /* delete from id2entry */
458         rs->sr_err = bdb_id2entry_delete( op->o_bd, lt2, e );
459         if ( rs->sr_err != 0 ) {
460 #ifdef NEW_LOGGING
461                 LDAP_LOG ( OPERATION, ERR, 
462                         "<=- bdb_delete: id2entry failed: %s (%d)\n", 
463                         db_strerror(rs->sr_err), rs->sr_err, 0 );
464 #else
465                 Debug(LDAP_DEBUG_TRACE,
466                         "<=- bdb_delete: id2entry failed: %s (%d)\n",
467                         db_strerror(rs->sr_err), rs->sr_err, 0 );
468 #endif
469                 switch( rs->sr_err ) {
470                 case DB_LOCK_DEADLOCK:
471                 case DB_LOCK_NOTGRANTED:
472                         goto retry;
473                 }
474                 rs->sr_text = "entry delete failed";
475                 rs->sr_err = LDAP_OTHER;
476                 goto return_results;
477         }
478
479         /* delete indices for old attributes */
480         rs->sr_err = bdb_index_entry_del( op, lt2, e );
481         if ( rs->sr_err != LDAP_SUCCESS ) {
482 #ifdef NEW_LOGGING
483                 LDAP_LOG ( OPERATION, ERR, 
484                         "<=- bdb_delete: index failed: %s (%d)\n", 
485                         db_strerror(rs->sr_err), rs->sr_err, 0 );
486 #else
487                 Debug( LDAP_DEBUG_TRACE,
488                         "<=- bdb_delete: index failed: %s (%d)\n", 
489                         db_strerror(rs->sr_err), rs->sr_err, 0 );
490 #endif
491                 switch( rs->sr_err ) {
492                 case DB_LOCK_DEADLOCK:
493                 case DB_LOCK_NOTGRANTED:
494                         goto retry;
495                 }
496                 rs->sr_text = "entry index delete failed";
497                 rs->sr_err = LDAP_OTHER;
498                 goto return_results;
499         }
500
501         if ( pdn.bv_len != 0 ) {
502                 parent_is_glue = is_entry_glue(p);
503                 rs->sr_err = bdb_cache_children( op, lt2, p );
504                 if ( rs->sr_err != DB_NOTFOUND ) {
505                         switch( rs->sr_err ) {
506                         case DB_LOCK_DEADLOCK:
507                         case DB_LOCK_NOTGRANTED:
508                                 goto retry;
509                         case 0:
510                                 break;
511                         default:
512 #ifdef NEW_LOGGING
513                                 LDAP_LOG ( OPERATION, ERR, 
514                                         "<=- bdb_delete: has_children failed %s (%d)\n",
515                                         db_strerror(rs->sr_err), rs->sr_err, 0 );
516 #else
517                                 Debug(LDAP_DEBUG_ARGS,
518                                         "<=- bdb_delete: has_children failed: %s (%d)\n",
519                                         db_strerror(rs->sr_err), rs->sr_err, 0 );
520 #endif
521                                 rs->sr_err = LDAP_OTHER;
522                                 rs->sr_text = "internal error";
523                                 goto return_results;
524                         }
525                         parent_is_leaf = 1;
526                 }
527                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
528                 p = NULL;
529         }
530
531         if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
532                 rs->sr_err = LDAP_OTHER;
533                 rs->sr_text = "txn_commit(2) failed";
534                 goto return_results;
535         }
536
537 #if 0   /* Do we want to reclaim deleted IDs? */
538         ldap_pvt_thread_mutex_lock( &bdb->bi_lastid_mutex );
539         if ( e->e_id == bdb->bi_lastid ) {
540                 bdb_last_id( op->o_bd, ltid );
541         }
542         ldap_pvt_thread_mutex_unlock( &bdb->bi_lastid_mutex );
543 #endif
544
545         if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
546                 rc = bdb_csn_commit( op, rs, ltid, ei, &suffix_ei,
547                         &ctxcsn_e, &ctxcsn_added, locker );
548                 switch ( rc ) {
549                 case BDB_CSN_ABORT :
550                         goto return_results;
551                 case BDB_CSN_RETRY :
552                         goto retry;
553                 }
554         }
555
556         if( op->o_noop ) {
557                 if ( ( rs->sr_err = TXN_ABORT( ltid ) ) != 0 ) {
558                         rs->sr_text = "txn_abort (no-op) failed";
559                 } else {
560                         rs->sr_err = LDAP_NO_OPERATION;
561                         goto return_results;
562                 }
563         } else {
564                 rc = bdb_cache_delete( &bdb->bi_cache, e, bdb->bi_dbenv,
565                         locker, &lock );
566                 switch( rc ) {
567                 case DB_LOCK_DEADLOCK:
568                 case DB_LOCK_NOTGRANTED:
569                         goto retry;
570                 }
571
572                 if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
573                         if ( ctxcsn_added ) {
574                                 bdb_cache_add( bdb, suffix_ei,
575                                         ctxcsn_e, (struct berval *)&slap_ldapsync_cn_bv, locker );
576                         }
577                 }
578
579                 if ( rs->sr_err == LDAP_SUCCESS && !op->o_no_psearch ) {
580                         ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock );
581                         LDAP_LIST_FOREACH( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
582                                 bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_DELETE );
583                         }
584                         ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock );
585                 }
586
587                 rs->sr_err = TXN_COMMIT( ltid, 0 );
588         }
589         ltid = NULL;
590         op->o_private = NULL;
591
592         if( rs->sr_err != 0 ) {
593 #ifdef NEW_LOGGING
594                 LDAP_LOG ( OPERATION, ERR, 
595                         "bdb_delete: txn_%s failed: %s (%d)\n",
596                         op->o_noop ? "abort (no-op)" : "commit",
597                         db_strerror(rs->sr_err), rs->sr_err );
598 #else
599                 Debug( LDAP_DEBUG_TRACE,
600                         "bdb_delete: txn_%s failed: %s (%d)\n",
601                         op->o_noop ? "abort (no-op)" : "commit",
602                         db_strerror(rs->sr_err), rs->sr_err );
603 #endif
604                 rs->sr_err = LDAP_OTHER;
605                 rs->sr_text = "commit failed";
606
607                 goto return_results;
608         }
609
610 #ifdef NEW_LOGGING
611         LDAP_LOG ( OPERATION, RESULTS, 
612                 "bdb_delete: deleted%s id=%08lx db=\"%s\"\n",
613                 op->o_noop ? " (no-op)" : "",
614                 e->e_id, e->e_dn );
615 #else
616         Debug( LDAP_DEBUG_TRACE,
617                 "bdb_delete: deleted%s id=%08lx dn=\"%s\"\n",
618                 op->o_noop ? " (no-op)" : "",
619                 e->e_id, e->e_dn );
620 #endif
621         rs->sr_err = LDAP_SUCCESS;
622         rs->sr_text = NULL;
623         if( num_ctrls ) rs->sr_ctrls = ctrls;
624
625 return_results:
626         send_ldap_result( op, rs );
627
628         if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) {
629                 ldap_pvt_thread_yield();
630                 TXN_CHECKPOINT( bdb->bi_dbenv,
631                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
632         }
633
634         if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
635                 op->o_delete_glue_parent = 1;
636         }
637
638 done:
639         if ( p )
640                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
641
642         /* free entry */
643         if( e != NULL ) {
644                 if ( rs->sr_err == LDAP_SUCCESS ) {
645                         /* Free the EntryInfo and the Entry */
646                         bdb_cache_delete_cleanup( &bdb->bi_cache, e );
647                 } else {
648                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
649                 }
650         }
651
652         if( ltid != NULL ) {
653                 TXN_ABORT( ltid );
654                 op->o_private = NULL;
655         }
656
657         if( preread_ctrl != NULL ) {
658                 slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, &op->o_tmpmemctx );
659                 slap_sl_free( *preread_ctrl, &op->o_tmpmemctx );
660         }
661         return rs->sr_err;
662 }