]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-ndb/modify.cpp
Partially revert prev commit, leave rs->sr_err == SLAPD_ABANDON
[openldap] / servers / slapd / back-ndb / modify.cpp
index d171bbcab50c63da53fb9c31dff5c756bd29ffcb..3733069c98ac0cef0f59719e2f550fd6df9ceba7 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2008 The OpenLDAP Foundation.
+ * Copyright 2008-2009 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
 #include "back-ndb.h"
 
+/* This is a copy from slapd/mods.c, but with compaction tweaked
+ * to swap values from the tail into deleted slots, to reduce the
+ * overall update traffic.
+ */
+static int
+ndb_modify_delete(
+       Entry   *e,
+       Modification    *mod,
+       int     permissive,
+       const char      **text,
+       char *textbuf, size_t textlen,
+       int *idx )
+{
+       Attribute       *a;
+       MatchingRule    *mr = mod->sm_desc->ad_type->sat_equality;
+       struct berval *cvals;
+       int             *id2 = NULL;
+       int             i, j, rc = 0, num;
+       unsigned flags;
+       char            dummy = '\0';
+
+       /* For ordered vals, we have no choice but to preserve order */
+       if ( mod->sm_desc->ad_type->sat_flags & SLAP_AT_ORDERED_VAL )
+               return modify_delete_vindex( e, mod, permissive, text,
+                       textbuf, textlen, idx );
+
+       /*
+        * If permissive is set, then the non-existence of an 
+        * attribute is not treated as an error.
+        */
+
+       /* delete the entire attribute */
+       if ( mod->sm_values == NULL ) {
+               rc = attr_delete( &e->e_attrs, mod->sm_desc );
+
+               if( permissive ) {
+                       rc = LDAP_SUCCESS;
+               } else if( rc != LDAP_SUCCESS ) {
+                       *text = textbuf;
+                       snprintf( textbuf, textlen,
+                               "modify/delete: %s: no such attribute",
+                               mod->sm_desc->ad_cname.bv_val );
+                       rc = LDAP_NO_SUCH_ATTRIBUTE;
+               }
+               return rc;
+       }
+
+       /* FIXME: Catch old code that doesn't set sm_numvals.
+        */
+       if ( !BER_BVISNULL( &mod->sm_values[mod->sm_numvals] )) {
+               for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ );
+               assert( mod->sm_numvals == i );
+       }
+       if ( !idx ) {
+               id2 = (int *)ch_malloc( mod->sm_numvals * sizeof( int ));
+               idx = id2;
+       }
+
+       if( mr == NULL || !mr->smr_match ) {
+               /* disallow specific attributes from being deleted if
+                       no equality rule */
+               *text = textbuf;
+               snprintf( textbuf, textlen,
+                       "modify/delete: %s: no equality matching rule",
+                       mod->sm_desc->ad_cname.bv_val );
+               rc = LDAP_INAPPROPRIATE_MATCHING;
+               goto return_result;
+       }
+
+       /* delete specific values - find the attribute first */
+       if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) {
+               if( permissive ) {
+                       rc = LDAP_SUCCESS;
+                       goto return_result;
+               }
+               *text = textbuf;
+               snprintf( textbuf, textlen,
+                       "modify/delete: %s: no such attribute",
+                       mod->sm_desc->ad_cname.bv_val );
+               rc = LDAP_NO_SUCH_ATTRIBUTE;
+               goto return_result;
+       }
+
+       if ( mod->sm_nvalues ) {
+               flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
+                       | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
+                       | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH;
+               cvals = mod->sm_nvalues;
+       } else {
+               flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX;
+               cvals = mod->sm_values;
+       }
+
+       /* Locate values to delete */
+       for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) {
+               unsigned sort;
+               rc = attr_valfind( a, flags, &cvals[i], &sort, NULL );
+               if ( rc == LDAP_SUCCESS ) {
+                       idx[i] = sort;
+               } else if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) {
+                       if ( permissive ) {
+                               idx[i] = -1;
+                               continue;
+                       }
+                       *text = textbuf;
+                       snprintf( textbuf, textlen,
+                               "modify/delete: %s: no such value",
+                               mod->sm_desc->ad_cname.bv_val );
+                       goto return_result;
+               } else {
+                       *text = textbuf;
+                       snprintf( textbuf, textlen,
+                               "modify/delete: %s: matching rule failed",
+                               mod->sm_desc->ad_cname.bv_val );
+                       goto return_result;
+               }
+       }
+
+       num = a->a_numvals;
+
+       /* Delete the values */
+       for ( i = 0; i < mod->sm_numvals; i++ ) {
+               /* Skip permissive values that weren't found */
+               if ( idx[i] < 0 )
+                       continue;
+               /* Skip duplicate delete specs */
+               if ( a->a_vals[idx[i]].bv_val == &dummy )
+                       continue;
+               /* delete value and mark it as gone */
+               free( a->a_vals[idx[i]].bv_val );
+               a->a_vals[idx[i]].bv_val = &dummy;
+               if( a->a_nvals != a->a_vals ) {
+                       free( a->a_nvals[idx[i]].bv_val );
+                       a->a_nvals[idx[i]].bv_val = &dummy;
+               }
+               a->a_numvals--;
+       }
+
+       /* compact array */
+       for ( i=0; i<num; i++ ) {
+               if ( a->a_vals[i].bv_val != &dummy )
+                       continue;
+               for ( --num; num > i && a->a_vals[num].bv_val == &dummy; num-- )
+                       ;
+               a->a_vals[i] = a->a_vals[num];
+               if ( a->a_nvals != a->a_vals )
+                       a->a_nvals[i] = a->a_nvals[num];
+       }
+
+       BER_BVZERO( &a->a_vals[num] );
+       if (a->a_nvals != a->a_vals) {
+               BER_BVZERO( &a->a_nvals[num] );
+       }
+
+       /* if no values remain, delete the entire attribute */
+       if ( !a->a_numvals ) {
+               if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) {
+                       /* Can never happen */
+                       *text = textbuf;
+                       snprintf( textbuf, textlen,
+                               "modify/delete: %s: no such attribute",
+                               mod->sm_desc->ad_cname.bv_val );
+                       rc = LDAP_NO_SUCH_ATTRIBUTE;
+               }
+       }
+return_result:
+       if ( id2 )
+               ch_free( id2 );
+       return rc;
+}
+
 int ndb_modify_internal(
        Operation *op,
        NdbArgs *NA,
@@ -40,8 +211,9 @@ int ndb_modify_internal(
        NdbAttrInfo **modai, *atmp;
        const NdbDictionary::Dictionary *myDict;
        const NdbDictionary::Table *myTable;
-       int got_oc = 0, nmods = 0, nai = 0, i;
-       int rc, err, indexed = 0;
+       int got_oc = 0, nmods = 0, nai = 0, i, j;
+       int rc, indexed = 0;
+       Attribute *old = NULL;
 
        Debug( LDAP_DEBUG_TRACE, "ndb_modify_internal: 0x%08lx: %s\n",
                NA->e->e_id, NA->e->e_dn, 0);
@@ -50,6 +222,8 @@ int ndb_modify_internal(
                return LDAP_INSUFFICIENT_ACCESS;
        }
 
+       old = attrs_dup( NA->e->e_attrs );
+
        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
                mod = &ml->sml_mod;
                nmods++;
@@ -59,11 +233,11 @@ int ndb_modify_internal(
                        Debug(LDAP_DEBUG_ARGS,
                                "ndb_modify_internal: add %s\n",
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
-                       err = modify_add_values( NA->e, mod, get_permissiveModify(op),
+                       rc = modify_add_values( NA->e, mod, get_permissiveModify(op),
                                text, textbuf, textlen );
-                       if( err != LDAP_SUCCESS ) {
+                       if( rc != LDAP_SUCCESS ) {
                                Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
-                                       err, *text, 0);
+                                       rc, *text, 0);
                        }
                        break;
 
@@ -71,12 +245,12 @@ int ndb_modify_internal(
                        Debug(LDAP_DEBUG_ARGS,
                                "ndb_modify_internal: delete %s\n",
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
-                       err = modify_delete_values( NA->e, mod, get_permissiveModify(op),
-                               text, textbuf, textlen );
-                       assert( err != LDAP_TYPE_OR_VALUE_EXISTS );
-                       if( err != LDAP_SUCCESS ) {
+                       rc = ndb_modify_delete( NA->e, mod, get_permissiveModify(op),
+                               text, textbuf, textlen, NULL );
+                       assert( rc != LDAP_TYPE_OR_VALUE_EXISTS );
+                       if( rc != LDAP_SUCCESS ) {
                                Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
-                                       err, *text, 0);
+                                       rc, *text, 0);
                        }
                        break;
 
@@ -84,11 +258,11 @@ int ndb_modify_internal(
                        Debug(LDAP_DEBUG_ARGS,
                                "ndb_modify_internal: replace %s\n",
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
-                       err = modify_replace_values( NA->e, mod, get_permissiveModify(op),
+                       rc = modify_replace_values( NA->e, mod, get_permissiveModify(op),
                                text, textbuf, textlen );
-                       if( err != LDAP_SUCCESS ) {
+                       if( rc != LDAP_SUCCESS ) {
                                Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
-                                       err, *text, 0);
+                                       rc, *text, 0);
                        }
                        break;
 
@@ -96,12 +270,12 @@ int ndb_modify_internal(
                        Debug(LDAP_DEBUG_ARGS,
                                "ndb_modify_internal: increment %s\n",
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
-                       err = modify_increment_values( NA->e, mod, get_permissiveModify(op),
+                       rc = modify_increment_values( NA->e, mod, get_permissiveModify(op),
                                text, textbuf, textlen );
-                       if( err != LDAP_SUCCESS ) {
+                       if( rc != LDAP_SUCCESS ) {
                                Debug(LDAP_DEBUG_ARGS,
                                        "ndb_modify_internal: %d %s\n",
-                                       err, *text, 0);
+                                       rc, *text, 0);
                        }
                        break;
 
@@ -111,18 +285,18 @@ int ndb_modify_internal(
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
                        mod->sm_op = LDAP_MOD_ADD;
 
-                       err = modify_add_values( NA->e, mod, get_permissiveModify(op),
+                       rc = modify_add_values( NA->e, mod, get_permissiveModify(op),
                                text, textbuf, textlen );
 
                        mod->sm_op = SLAP_MOD_SOFTADD;
 
-                       if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
-                               err = LDAP_SUCCESS;
+                       if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
+                               rc = LDAP_SUCCESS;
                        }
 
-                       if( err != LDAP_SUCCESS ) {
+                       if( rc != LDAP_SUCCESS ) {
                                Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
-                                       err, *text, 0);
+                                       rc, *text, 0);
                        }
                        break;
 
@@ -130,13 +304,14 @@ int ndb_modify_internal(
                        Debug(LDAP_DEBUG_ANY, "ndb_modify_internal: invalid op %d\n",
                                mod->sm_op, 0, 0);
                        *text = "Invalid modify operation";
-                       err = LDAP_OTHER;
+                       rc = LDAP_OTHER;
                        Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
-                               err, *text, 0);
+                               rc, *text, 0);
                }
 
-               if ( err != LDAP_SUCCESS ) {
-                       return err; 
+               if ( rc != LDAP_SUCCESS ) {
+                       attrs_free( old );
+                       return rc; 
                }
 
                /* If objectClass was modified, reset the flags */
@@ -147,7 +322,7 @@ int ndb_modify_internal(
        }
 
        /* check that the entry still obeys the schema */
-       rc = entry_schema_check( op, NA->e, NULL, get_relax(op), 0,
+       rc = entry_schema_check( op, NA->e, NULL, get_relax(op), 0, NULL,
                text, textbuf, textlen );
        if ( rc != LDAP_SUCCESS || op->o_noop ) {
                if ( rc != LDAP_SUCCESS ) {
@@ -155,6 +330,7 @@ int ndb_modify_internal(
                                "entry failed schema check: %s\n",
                                *text, 0, 0 );
                }
+               attrs_free( old );
                return rc;
        }
 
@@ -183,36 +359,52 @@ int ndb_modify_internal(
 
        if ( got_oc || indexed ) {
                rc = ndb_entry_put_info( op->o_bd, NA, 1 );
-               if ( rc ) return rc;
+               if ( rc ) {
+                       attrs_free( old );
+                       return rc;
+               }
        }
 
        myDict = NA->ndb->getDictionary();
 
-       /* One operation per table... */
-       for ( i=0; i<nai; i++ ) {
-               NdbOperation *myOp;
-               int j;
+       /* sort modai so that OcInfo's are contiguous */
+       {
+               int j, k;
+               for ( i=0; i<nai; i++ ) {
+                       for ( j=i+1; j<nai; j++ ) {
+                               if ( modai[i]->na_oi == modai[j]->na_oi )
+                                       continue;
+                               for ( k=j+1; k<nai; k++ ) {
+                                       if ( modai[i]->na_oi == modai[k]->na_oi ) {
+                                               atmp = modai[j];
+                                               modai[j] = modai[k];
+                                               modai[k] = atmp;
+                                               break;
+                                       }
+                               }
+                               /* there are no more na_oi's that match modai[i] */
+                               if ( k == nai ) {
+                                       i = j;
+                               }
+                       }
+               }
+       }
 
-               if ( !modai[i] ) continue;
+       /* One call per table... */
+       for ( i=0; i<nai; i += j ) {
                atmp = modai[i];
-               modai[i] = NULL;
+               for ( j=i+1; j<nai; j++ )
+                       if ( atmp->na_oi != modai[j]->na_oi )
+                               break;
+               j -= i;
                myTable = myDict->getTable( atmp->na_oi->no_table.bv_val );
-               if ( !myTable ) continue;
-               myOp = NULL;
-               nmods = 0;
-               rc = ndb_oc_attrs( NA->txn, myTable, NA->e, atmp->na_oi, &atmp, 1, 1, &nmods, &myOp );
-               if ( rc ) return rc;
-               for ( j=i+1; j<nai; j++ ) {
-                       if ( !modai[j] ) continue;
-                       if ( modai[j]->na_oi == atmp->na_oi ) {
-                               atmp = modai[j];
-                               modai[j] = NULL;
-                               rc = ndb_oc_attrs( NA->txn, myTable, NA->e, atmp->na_oi, &atmp, 1, 1, &nmods, &myOp );
-                               if ( rc ) return rc;
-                       }
-               }
+               if ( !myTable )
+                       continue;
+               rc = ndb_oc_attrs( NA->txn, myTable, NA->e, atmp->na_oi, &modai[i], j, old );
+               if ( rc ) break;
        }
-       return 0;
+       attrs_free( old );
+       return rc;
 }
 
 
@@ -236,8 +428,6 @@ ndb_back_modify( Operation *op, SlapReply *rs )
        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
        int num_ctrls = 0;
 
-       int rc;
-
        Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(ndb_back_modify) ": %s\n",
                op->o_req_dn.bv_val, 0, 0 );
 
@@ -269,7 +459,7 @@ retry:      /* transaction retry */
                        goto return_results;
                }
                if ( NA.ocs ) {
-                       ber_bvarray_free( NA.ocs );
+                       ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
                }
                ndb_trans_backoff( ++num_retries );
        }
@@ -288,7 +478,7 @@ retry:      /* transaction retry */
        }
 
        /* get entry or ancestor */
-       rs->sr_err = ndb_entry_get_info( op->o_bd, &NA, 0, &matched );
+       rs->sr_err = ndb_entry_get_info( op, &NA, 0, &matched );
        switch( rs->sr_err ) {
        case 0:
                break;
@@ -297,6 +487,8 @@ retry:      /* transaction retry */
                        "<=- ndb_back_modify: no such object %s\n",
                        op->o_req_dn.bv_val, 0, 0 );
                rs->sr_matched = matched.bv_val;
+               if (NA.ocs )
+                       ndb_check_referral( op, rs, &NA );
                goto return_results;
 #if 0
        case DB_LOCK_DEADLOCK:
@@ -313,7 +505,7 @@ retry:      /* transaction retry */
        }
 
        /* acquire and lock entry */
-       rs->sr_err = ndb_entry_get_data( op->o_bd, &NA, 1 );
+       rs->sr_err = ndb_entry_get_data( op, &NA, 1 );
 
        if ( !manageDSAit && is_entry_referral( &e ) ) {
                /* entry is a referral, don't allow modify */
@@ -392,13 +584,15 @@ retry:    /* transaction retry */
        }
 
        if( op->o_noop ) {
-               if ( ( rs->sr_err = NA.txn->execute( Rollback ) ) != 0 ) {
+               if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback,
+                       NdbOperation::AbortOnError, 1 )) != 0 ) {
                        rs->sr_text = "txn_abort (no-op) failed";
                } else {
                        rs->sr_err = LDAP_X_NO_OPERATION;
                }
        } else {
-               if ( ( rs->sr_err = NA.txn->execute( Commit ) ) != 0 ) {
+               if (( rs->sr_err=NA.txn->execute( NdbTransaction::Commit,
+                       NdbOperation::AbortOnError, 1 )) != 0 ) {
                        rs->sr_text = "txn_commit failed";
                } else {
                        rs->sr_err = LDAP_SUCCESS;
@@ -427,7 +621,7 @@ retry:      /* transaction retry */
 
 return_results:
        if ( NA.ocs ) {
-               ber_bvarray_free( NA.ocs );
+               ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
                NA.ocs = NULL;
        }