]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-bdb/delete.c
ITS#5322 don't try to free a NULL locker
[openldap] / servers / slapd / back-bdb / delete.c
index 5e70633adf88749fb1990fb76656cc09e342c260..dfa50bed0a638fdf007d94823ebc39fcef1c7399 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2000-2005 The OpenLDAP Foundation.
+ * Copyright 2000-2008 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,7 @@ bdb_delete( Operation *op, SlapReply *rs )
        struct bdb_op_info opinfo = {0};
        ID      eid;
 
-       u_int32_t       locker = 0;
+       BDB_LOCKER      locker = 0;
        DB_LOCK         lock, plock;
 
        int             num_retries = 0;
@@ -52,13 +52,55 @@ bdb_delete( Operation *op, SlapReply *rs )
        int     parent_is_glue = 0;
        int parent_is_leaf = 0;
 
-       ctrls[num_ctrls] = 0;
+#ifdef LDAP_X_TXN
+       int settle = 0;
+#endif
 
        Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(bdb_delete) ": %s\n",
                op->o_req_dn.bv_val, 0, 0 );
 
+#ifdef LDAP_X_TXN
+       if( op->o_txnSpec ) {
+               /* acquire connection lock */
+               ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
+               if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
+                       rs->sr_text = "invalid transaction identifier";
+                       rs->sr_err = LDAP_X_TXN_ID_INVALID;
+                       goto txnReturn;
+               } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
+                       settle=1;
+                       goto txnReturn;
+               }
+
+               if( op->o_conn->c_txn_backend == NULL ) {
+                       op->o_conn->c_txn_backend = op->o_bd;
+
+               } else if( op->o_conn->c_txn_backend != op->o_bd ) {
+                       rs->sr_text = "transaction cannot span multiple database contexts";
+                       rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
+                       goto txnReturn;
+               }
+
+               /* insert operation into transaction */
+
+               rs->sr_text = "transaction specified";
+               rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
+
+txnReturn:
+               /* release connection lock */
+               ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
+
+               if( !settle ) {
+                       send_ldap_result( op, rs );
+                       return rs->sr_err;
+               }
+       }
+#endif
+
+       ctrls[num_ctrls] = 0;
+
        /* allocate CSN */
-       if ( !SLAP_SHADOW( op->o_bd )) {
+       if ( BER_BVISNULL( &op->o_csn ) ) {
                struct berval csn;
                char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
 
@@ -95,7 +137,6 @@ retry:       /* transaction retry */
                }
                parent_is_glue = 0;
                parent_is_leaf = 0;
-               ldap_pvt_thread_yield();
                bdb_trans_backoff( ++num_retries );
        }
 
@@ -116,7 +157,6 @@ retry:      /* transaction retry */
 
        opinfo.boi_bdb = op->o_bd;
        opinfo.boi_txn = ltid;
-       opinfo.boi_locker = locker;
        opinfo.boi_err = 0;
        opinfo.boi_acl_cache = op->o_do_not_cache;
        op->o_private = &opinfo;
@@ -310,7 +350,11 @@ retry:     /* transaction retry */
                        Debug( LDAP_DEBUG_TRACE,
                                "<=- " LDAP_XSTRING(bdb_delete) ": pre-read "
                                "failed!\n", 0, 0, 0 );
-                       goto return_results;
+                       if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
+                               /* FIXME: is it correct to abort
+                                * operation if control fails? */
+                               goto return_results;
+                       }
                }
        }
 
@@ -327,6 +371,9 @@ retry:      /* transaction retry */
                goto return_results;
        }
 
+       BDB_LOG_PRINTF( bdb->bi_dbenv, lt2, "slapd Starting delete %s(%d)",
+               e->e_nname.bv_val, e->e_id );
+
        /* Can't do it if we have kids */
        rs->sr_err = bdb_cache_children( op, lt2, e );
        if( rs->sr_err != DB_NOTFOUND ) {
@@ -369,34 +416,55 @@ retry:    /* transaction retry */
                goto return_results;
        }
 
-       /* delete from id2entry */
-       rs->sr_err = bdb_id2entry_delete( op->o_bd, lt2, e );
-       if ( rs->sr_err != 0 ) {
+       /* delete indices for old attributes */
+       rs->sr_err = bdb_index_entry_del( op, lt2, e );
+       if ( rs->sr_err != LDAP_SUCCESS ) {
                Debug(LDAP_DEBUG_TRACE,
-                       "<=- " LDAP_XSTRING(bdb_delete) ": id2entry failed: "
+                       "<=- " LDAP_XSTRING(bdb_delete) ": index failed: "
                        "%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
                switch( rs->sr_err ) {
                case DB_LOCK_DEADLOCK:
                case DB_LOCK_NOTGRANTED:
                        goto retry;
                }
-               rs->sr_text = "entry delete failed";
+               rs->sr_text = "entry index delete failed";
                rs->sr_err = LDAP_OTHER;
                goto return_results;
        }
 
-       /* delete indices for old attributes */
-       rs->sr_err = bdb_index_entry_del( op, lt2, e );
+       /* fixup delete CSN */
+       if ( !SLAP_SHADOW( op->o_bd )) {
+               struct berval vals[2];
+
+               assert( !BER_BVISNULL( &op->o_csn ) );
+               vals[0] = op->o_csn;
+               BER_BVZERO( &vals[1] );
+               rs->sr_err = bdb_index_values( op, lt2, slap_schema.si_ad_entryCSN,
+                       vals, 0, SLAP_INDEX_ADD_OP );
        if ( rs->sr_err != LDAP_SUCCESS ) {
+                       switch( rs->sr_err ) {
+                       case DB_LOCK_DEADLOCK:
+                       case DB_LOCK_NOTGRANTED:
+                               goto retry;
+                       }
+                       rs->sr_text = "entryCSN index update failed";
+                       rs->sr_err = LDAP_OTHER;
+                       goto return_results;
+               }
+       }
+
+       /* delete from id2entry */
+       rs->sr_err = bdb_id2entry_delete( op->o_bd, lt2, e );
+       if ( rs->sr_err != 0 ) {
                Debug( LDAP_DEBUG_TRACE,
-                       "<=- " LDAP_XSTRING(bdb_delete) ": index failed: "
+                       "<=- " LDAP_XSTRING(bdb_delete) ": id2entry failed: "
                        "%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
                switch( rs->sr_err ) {
                case DB_LOCK_DEADLOCK:
                case DB_LOCK_NOTGRANTED:
                        goto retry;
                }
-               rs->sr_text = "entry index delete failed";
+               rs->sr_text = "entry delete failed";
                rs->sr_err = LDAP_OTHER;
                goto return_results;
        }
@@ -426,6 +494,9 @@ retry:      /* transaction retry */
                p = NULL;
        }
 
+       BDB_LOG_PRINTF( bdb->bi_dbenv, lt2, "slapd Commit1 delete %s(%d)",
+               e->e_nname.bv_val, e->e_id );
+
        if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
                rs->sr_err = LDAP_OTHER;
                rs->sr_text = "txn_commit(2) failed";
@@ -446,12 +517,16 @@ retry:    /* transaction retry */
                if ( ( rs->sr_err = TXN_ABORT( ltid ) ) != 0 ) {
                        rs->sr_text = "txn_abort (no-op) failed";
                } else {
-                       rs->sr_err = LDAP_NO_OPERATION;
+                       rs->sr_err = LDAP_X_NO_OPERATION;
+                       ltid = NULL;
                        goto return_results;
                }
        } else {
-               rc = bdb_cache_delete( &bdb->bi_cache, e, bdb->bi_dbenv,
-                       locker, &lock );
+
+               BDB_LOG_PRINTF( bdb->bi_dbenv, ltid, "slapd Cache delete %s(%d)",
+                       e->e_nname.bv_val, e->e_id );
+
+               rc = bdb_cache_delete( bdb, e, locker, &lock );
                switch( rc ) {
                case DB_LOCK_DEADLOCK:
                case DB_LOCK_NOTGRANTED:
@@ -463,6 +538,9 @@ retry:      /* transaction retry */
        ltid = NULL;
        op->o_private = NULL;
 
+       BDB_LOG_PRINTF( bdb->bi_dbenv, NULL, "slapd Committed delete %s(%d)",
+               e->e_nname.bv_val, e->e_id );
+
        if( rs->sr_err != 0 ) {
                Debug( LDAP_DEBUG_TRACE,
                        LDAP_XSTRING(bdb_delete) ": txn_%s failed: %s (%d)\n",
@@ -502,20 +580,18 @@ return_results:
 
        if( ltid != NULL ) {
                TXN_ABORT( ltid );
-               op->o_private = NULL;
        }
+       op->o_private = NULL;
 
        send_ldap_result( op, rs );
-       if ( !SLAP_SHADOW( op->o_bd ))
-               slap_graduate_commit_csn( op );
+       slap_graduate_commit_csn( op );
 
-       if( preread_ctrl != NULL ) {
+       if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
                slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
                slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
        }
 
-       if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) {
-               ldap_pvt_thread_yield();
+       if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp_kbyte ) {
                TXN_CHECKPOINT( bdb->bi_dbenv,
                        bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
        }