X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-bdb%2Fmodify.c;h=f84f2074794edc75f1d7347f574b6734cb4e6349;hb=ac7ac5acefdf859251a37274167200374d37cba9;hp=0d188d626eedb8cb987fd6a4704616044d1c6f3f;hpb=ece7452b05fcbbb14823e113b683365a59f81f05;p=openldap diff --git a/servers/slapd/back-bdb/modify.c b/servers/slapd/back-bdb/modify.c index 0d188d626e..f84f207479 100644 --- a/servers/slapd/back-bdb/modify.c +++ b/servers/slapd/back-bdb/modify.c @@ -14,6 +14,9 @@ #include "back-bdb.h" #include "external.h" +#define INDEXED 0x2000 +#define NULLIFIED 0x4000 + int bdb_modify_internal( Operation *op, DB_TXN *tid, @@ -41,6 +44,7 @@ int bdb_modify_internal( return LDAP_INSUFFICIENT_ACCESS; } + /* save_attrs will be disposed of by bdb_cache_modify */ save_attrs = e->e_attrs; e->e_attrs = attrs_dup( e->e_attrs ); @@ -122,6 +126,9 @@ int bdb_modify_internal( err = modify_add_values( e, mod, get_permissiveModify(op), text, textbuf, textlen ); + + mod->sm_op = SLAP_MOD_SOFTADD; + if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) { err = LDAP_SUCCESS; } @@ -167,17 +174,6 @@ int bdb_modify_internal( if ( mod->sm_desc == slap_schema.si_ad_objectClass ) { e->e_ocflags = 0; } - - /* check if modified attribute was indexed - * but not in case of NOOP... */ - err = bdb_index_is_indexed( op->o_bd, mod->sm_desc ); - if ( err == LDAP_SUCCESS && !op->o_noop ) { - ap = attr_find( save_attrs, mod->sm_desc ); - if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL; - - ap = attr_find( e->e_attrs, mod->sm_desc ); - if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD; - } } /* check that the entry still obeys the schema */ @@ -203,62 +199,87 @@ int bdb_modify_internal( } /* update the indices of the modified attributes */ - - /* start with deleting the old index entries */ - for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) { - if ( ap->a_flags & SLAP_ATTR_IXDEL ) { - rc = bdb_index_values( op, tid, ap->a_desc, - ap->a_nvals, - e->e_id, SLAP_INDEX_DELETE_OP ); - if ( rc != LDAP_SUCCESS ) { - attrs_free( e->e_attrs ); - e->e_attrs = save_attrs; -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, - "bdb_modify_internal: attribute index delete failure\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_ANY, - "Attribute index delete failure", - 0, 0, 0 ); -#endif - return rc; + if ( !op->o_noop ) { + Modifications *m2; + + /* First look for any deletes that would nullify any adds + * in this request. I.e., deleting an entire attribute after + * assigning some values to it. + */ + for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { + if (bdb_index_is_indexed( op->o_bd, ml->sml_desc )) + continue; + switch ( ml->sml_op ) { + case LDAP_MOD_DELETE: + /* If just deleting specific values, ignore */ + if ( ml->sml_bvalues ) break; + case LDAP_MOD_REPLACE: + for ( m2 = modlist; m2 != ml; m2 = m2->sml_next ) { + if ( m2->sml_desc == ml->sml_desc && + m2->sml_op != LDAP_MOD_DELETE ) + m2->sml_op |= NULLIFIED; + } + break; } - ap->a_flags &= ~SLAP_ATTR_IXDEL; + ml->sml_op |= INDEXED; } - } - - /* add the new index entries */ - for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) { - if (ap->a_flags & SLAP_ATTR_IXADD) { - rc = bdb_index_values( op, tid, ap->a_desc, - ap->a_nvals, - e->e_id, SLAP_INDEX_ADD_OP ); + /* Now index the modifications */ + for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { + if ( ! (ml->sml_op & INDEXED) ) continue; + ml->sml_op ^= INDEXED; + switch ( ml->sml_op ) { + case LDAP_MOD_DELETE: + if ( ml->sml_bvalues ) { + rc = bdb_index_values( op, tid, ml->sml_desc, + ml->sml_nvalues ? ml->sml_nvalues : ml->sml_bvalues, + e->e_id, SLAP_INDEX_DELETE_OP ); + break; + } + /* FALLTHRU */ + case LDAP_MOD_REPLACE: + /* A nullified replace still does its delete action */ + case LDAP_MOD_REPLACE | NULLIFIED: + ap = attr_find( save_attrs, ml->sml_desc ); + if ( ap != NULL ) { + rc = bdb_index_values( op, tid, ap->a_desc, + ap->a_nvals, + e->e_id, SLAP_INDEX_DELETE_OP ); + } else { + rc = LDAP_SUCCESS; + } + if ( rc || ml->sml_op == LDAP_MOD_DELETE || + (ml->sml_op & NULLIFIED)) + break; + /* FALLTHRU */ + case LDAP_MOD_ADD: + case SLAP_MOD_SOFTADD: + rc = bdb_index_values( op, tid, ml->sml_desc, + ml->sml_nvalues ? ml->sml_nvalues : ml->sml_bvalues, + e->e_id, SLAP_INDEX_ADD_OP ); + break; + } + ml->sml_op &= ~NULLIFIED; if ( rc != LDAP_SUCCESS ) { attrs_free( e->e_attrs ); e->e_attrs = save_attrs; #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, - "bdb_modify_internal: attribute index add failure\n", + "bdb_modify_internal: attribute index update failure\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, - "Attribute index add failure", + "Attribute index update failure", 0, 0, 0 ); #endif - return rc; + /* reset our flags */ + for (; ml; ml=ml->sml_next ) { + ml->sml_op &= ~(INDEXED | NULLIFIED); + } + break; } - ap->a_flags &= ~SLAP_ATTR_IXADD; } } - /* If we've done repeated mods on a cached entry, then e_attrs - * is no longer contiguous with the entry. - */ - if( (void *) save_attrs != (void *) (e+1)) { - attrs_free( save_attrs ); - } - return rc; } @@ -267,13 +288,14 @@ int bdb_modify( Operation *op, SlapReply *rs ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; - Entry *matched = NULL; Entry *e = NULL; + EntryInfo *ei = NULL; int manageDSAit = get_manageDSAit( op ); char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof textbuf; - DB_TXN *ltid = NULL; + DB_TXN *ltid = NULL, *lt2; struct bdb_op_info opinfo; + Entry dummy; u_int32_t locker = 0; DB_LOCK lock; @@ -294,8 +316,8 @@ bdb_modify( Operation *op, SlapReply *rs ) if( 0 ) { retry: /* transaction retry */ if( e != NULL ) { - bdb_cache_delete_entry(&bdb->bi_cache, e); bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e); + e = NULL; } #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, DETAIL1, "bdb_modify: retrying...\n", 0, 0, 0 ); @@ -353,8 +375,9 @@ retry: /* transaction retry */ opinfo.boi_acl_cache = op->o_do_not_cache; op->o_private = &opinfo; - /* get entry */ - rs->sr_err = bdb_dn2entry_w( op->o_bd, ltid, &op->o_req_ndn, &e, &matched, 0, locker, &lock ); + /* get entry or ancestor */ + rs->sr_err = bdb_dn2entry( op->o_bd, ltid, &op->o_req_ndn, &ei, 1, + locker, &lock, op->o_tmpmemctx ); if ( rs->sr_err != 0 ) { #ifdef NEW_LOGGING @@ -381,15 +404,16 @@ retry: /* transaction retry */ } } + e = ei->bei_e; /* acquire and lock entry */ - if ( e == NULL ) { - if ( matched != NULL ) { - rs->sr_matched = ch_strdup( matched->e_dn ); - rs->sr_ref = is_entry_referral( matched ) - ? get_entry_referrals( op, matched ) + if ( rs->sr_err == DB_NOTFOUND ) { + if ( e != NULL ) { + rs->sr_matched = ch_strdup( e->e_dn ); + rs->sr_ref = is_entry_referral( e ) + ? get_entry_referrals( op, e ) : NULL; - bdb_unlocked_cache_return_entry_r (&bdb->bi_cache, matched); - matched = NULL; + bdb_unlocked_cache_return_entry_r (&bdb->bi_cache, e); + e = NULL; } else { rs->sr_ref = referral_rewrite( default_referral, @@ -437,9 +461,27 @@ retry: /* transaction retry */ } #endif + /* nested transaction */ + rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, <2, + bdb->bi_db_opflags ); + rs->sr_text = NULL; + if( rs->sr_err != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, + "bdb_modify: txn_begin(2) failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_modify: txn_begin(2) failed: %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); +#endif + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + goto return_results; + } /* Modify the entry */ - rs->sr_err = bdb_modify_internal( op, ltid, op->oq_modify.rs_modlist, e, - &rs->sr_text, textbuf, textlen ); + dummy = *e; + rs->sr_err = bdb_modify_internal( op, lt2, op->oq_modify.rs_modlist, + &dummy, &rs->sr_text, textbuf, textlen ); if( rs->sr_err != LDAP_SUCCESS ) { #ifdef NEW_LOGGING @@ -462,7 +504,7 @@ retry: /* transaction retry */ } /* change the entry itself */ - rs->sr_err = bdb_id2entry_update( op->o_bd, ltid, e ); + rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, &dummy ); if ( rs->sr_err != 0 ) { #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, @@ -480,6 +522,11 @@ retry: /* transaction retry */ rs->sr_text = "entry update failed"; goto return_results; } + if ( TXN_COMMIT( lt2, 0 ) != 0 ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "txn_commit(2) failed"; + goto return_results; + } if( op->o_noop ) { if ( ( rs->sr_err = TXN_ABORT( ltid ) ) != 0 ) { @@ -489,6 +536,7 @@ retry: /* transaction retry */ rs->sr_err = LDAP_SUCCESS; } } else { + bdb_cache_modify( e, dummy.e_attrs, bdb->bi_dbenv, locker, &lock ); rs->sr_err = TXN_COMMIT( ltid, 0 ); } ltid = NULL;