From ebd750b077547bb63d79c26aadc2e5322f00c0f3 Mon Sep 17 00:00:00 2001 From: Ludwig Krispenz Date: Wed, 20 Mar 2013 14:46:33 +0100 Subject: [PATCH] Reduce replication meta data stored in entry, cf ticket 561 --- ldap/servers/slapd/entry.c | 10 + ldap/servers/slapd/entrywsi.c | 553 ++++++++++++++++++++++++++-------------- ldap/servers/slapd/proto-slap.h | 1 + ldap/servers/slapd/valueset.c | 9 + 4 files changed, 378 insertions(+), 195 deletions(-) diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c index 1fde838..41e46f0 100644 --- a/ldap/servers/slapd/entry.c +++ b/ldap/servers/slapd/entry.c @@ -1717,6 +1717,16 @@ entry2str_internal_put_attrlist( const Slapi_Attr *attrlist, int attr_state, int else { /* There were no present values on which to place the ADCSN, so we put it on the first deleted value. */ + if ( valueset_isempty(&a->a_deleted_values)) { + /* this means the entry is deleted and has no more attributes, + * when writing the attr to disk we would loose the AD-csn. + * Add an empty value to the set of deleted values. This will + * never be seen by any client. It will never be moved to the + * present values and is only used to preserve the AD-csn + */ + valueset_add_string (&a->a_deleted_values, "", CSN_TYPE_VALUE_DELETED, a->a_deletioncsn); + } + entry2str_internal_put_valueset(a->a_type, a->a_deletioncsn, CSN_TYPE_ATTRIBUTE_DELETED, attr_state, &a->a_deleted_values, VALUE_DELETED, ecur, typebuf, typebuf_len, entry2str_ctrl); } } diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c index 578cb4f..c786b87 100644 --- a/ldap/servers/slapd/entrywsi.c +++ b/ldap/servers/slapd/entrywsi.c @@ -419,25 +419,129 @@ entry_add_present_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a) * Preserves LDAP Information Model constraints, * returning an LDAP result code. */ +static void resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state); +static void resolve_attribute_state_deleted_to_present(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate); +static void resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate); +static void resolve_attribute_state_to_present_or_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate, int attribute_state); +static int entry_add_present_values_wsi_single_valued(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags); +static int entry_add_present_values_wsi_multi_valued(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags); static int entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags) { + int retVal = LDAP_SUCCESS; + Slapi_Attr *a= NULL; + int attr_state= entry_attr_find_wsi(e, type, &a); + if (ATTRIBUTE_NOTFOUND == attr_state) + { + /* Create a new attribute */ + a = slapi_attr_new(); + slapi_attr_init(a, type); + attrlist_add(&e->e_attrs, a); + } + + if(slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE)) + { + retVal = entry_add_present_values_wsi_single_valued( e, type, bervals, csn, urp, 0 ); + } + else + { + retVal = entry_add_present_values_wsi_multi_valued( e, type, bervals, csn, urp, 0 ); + } + return retVal; +} +static int +entry_add_present_values_wsi_single_valued(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags) +{ int retVal= LDAP_SUCCESS; - Slapi_Value **valuestoadd = NULL; - valuearray_init_bervalarray(bervals,&valuestoadd); /* JCM SLOW FUNCTION */ + Slapi_Value **valuestoadd = NULL; + valuearray_init_bervalarray(bervals,&valuestoadd); /* JCM SLOW FUNCTION */ if(!valuearray_isempty(valuestoadd)) { Slapi_Attr *a= NULL; long a_flags_orig; int attr_state= entry_attr_find_wsi(e, type, &a); - if (ATTRIBUTE_NOTFOUND == attr_state) + a_flags_orig = a->a_flags; + a->a_flags |= flags; + /* Check if the type of the to-be-added values has DN syntax or not. */ + if (slapi_attr_is_dn_syntax_attr(a)) { + valuearray_dn_normalize_value(valuestoadd); + a->a_flags |= SLAPI_ATTR_FLAG_NORMALIZED_CES; + } + if(urp) { - /* Create a new attribute */ - a = slapi_attr_new(); - slapi_attr_init(a, type); - attrlist_add(&e->e_attrs, a); + valueset_remove_valuearray (&a->a_present_values, a, valuestoadd, + SLAPI_VALUE_FLAG_IGNOREERROR | + SLAPI_VALUE_FLAG_PRESERVECSNSET, NULL); + valueset_remove_valuearray (&a->a_deleted_values, a, valuestoadd, + SLAPI_VALUE_FLAG_IGNOREERROR | + SLAPI_VALUE_FLAG_PRESERVECSNSET, NULL); + valuearray_update_csn (valuestoadd,CSN_TYPE_VALUE_UPDATED,csn); + valueset_add_valuearray_ext(&a->a_present_values, valuestoadd, SLAPI_VALUE_FLAG_PASSIN); + slapi_ch_free ( (void **)&valuestoadd ); + + /* + * Now delete non-RDN values from a->a_present_values; and + * restore possible RDN values from a->a_deleted_values + */ + resolve_attribute_state_single_valued(e, a, attr_state); + retVal= LDAP_SUCCESS; } - a_flags_orig = a->a_flags; + else + { + Slapi_Value **deletedvalues= NULL; + switch(attr_state) + { + case ATTRIBUTE_PRESENT: + /* The attribute is already on the present list */ + break; + case ATTRIBUTE_DELETED: + /* Move the deleted attribute onto the present list */ + entry_deleted_attribute_to_present_attribute(e, a); + break; + case ATTRIBUTE_NOTFOUND: + /* No-op - attribute was initialized & added to entry above */ + break; + } + /* Check if any of the values to be added are on the deleted list */ + valueset_remove_valuearray(&a->a_deleted_values, + a, valuestoadd, + SLAPI_VALUE_FLAG_IGNOREERROR|SLAPI_VALUE_FLAG_USENEWVALUE, + &deletedvalues); /* JCM Check return code */ + if(deletedvalues!=NULL && deletedvalues[0]!=NULL) + { + /* Some of the values to be added were on the deleted list */ + Slapi_Value **v= NULL; + Slapi_ValueSet vs; + /* Add each deleted value to the present list */ + valuearray_update_csn(deletedvalues,CSN_TYPE_VALUE_UPDATED,csn); + valueset_add_valuearray_ext(&a->a_present_values, deletedvalues, SLAPI_VALUE_FLAG_PASSIN); + /* Remove the deleted values from the values to add */ + valueset_set_valuearray_passin(&vs,valuestoadd); + valueset_remove_valuearray(&vs, a, deletedvalues, SLAPI_VALUE_FLAG_IGNOREERROR, &v); + valuestoadd= valueset_get_valuearray(&vs); + valuearray_free(&v); + slapi_ch_free((void **)&deletedvalues); + } + valuearray_update_csn(valuestoadd,CSN_TYPE_VALUE_UPDATED,csn); + retVal= attr_add_valuearray(a, valuestoadd, slapi_entry_get_dn_const(e)); + valuearray_free(&valuestoadd); + } + a->a_flags = a_flags_orig; + } + return(retVal); +} +static int +entry_add_present_values_wsi_multi_valued(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags) +{ + int retVal= LDAP_SUCCESS; + Slapi_Value **valuestoadd = NULL; + valuearray_init_bervalarray(bervals,&valuestoadd); /* JCM SLOW FUNCTION */ + if(!valuearray_isempty(valuestoadd)) + { + Slapi_Attr *a= NULL; + long a_flags_orig; + int attr_state= entry_attr_find_wsi(e, type, &a); + a_flags_orig = a->a_flags; a->a_flags |= flags; /* Check if the type of the to-be-added values has DN syntax or not. */ if (slapi_attr_is_dn_syntax_attr(a)) { @@ -462,16 +566,14 @@ entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **b SLAPI_VALUE_FLAG_IGNOREERROR | SLAPI_VALUE_FLAG_PRESERVECSNSET, NULL); - /* Append the pending values to a->a_present_values */ + /* Now add the values in values to add to present or deleted + * values, depending on their csnset */ valuearray_update_csn (valuestoadd,CSN_TYPE_VALUE_UPDATED,csn); - valueset_add_valuearray_ext(&a->a_present_values, valuestoadd, SLAPI_VALUE_FLAG_PASSIN); + + resolve_attribute_state_to_present_or_deleted(e, a, valuestoadd, attr_state); + slapi_ch_free ( (void **)&valuestoadd ); - /* - * Now delete non-RDN values from a->a_present_values; and - * restore possible RDN values from a->a_deleted_values - */ - resolve_attribute_state(e, a, attr_state, 0); retVal= LDAP_SUCCESS; } else @@ -526,13 +628,155 @@ entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **b * returning an LDAP result code. */ static int +entry_delete_present_values_wsi_single_valued(Slapi_Entry *e, const char *type, struct berval **vals, const CSN *csn, int urp, int mod_op, struct berval **replacevals); +static int +entry_delete_present_values_wsi_multi_valued(Slapi_Entry *e, const char *type, struct berval **vals, const CSN *csn, int urp, int mod_op, struct berval **replacevals); +static int entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **vals, const CSN *csn, int urp, int mod_op, struct berval **replacevals) { int retVal= LDAP_SUCCESS; Slapi_Attr *a= NULL; int attr_state= entry_attr_find_wsi(e, type, &a); + if(attr_state==ATTRIBUTE_PRESENT || (attr_state==ATTRIBUTE_DELETED && urp)) { + if(slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE)) + retVal = entry_delete_present_values_wsi_single_valued(e, type, vals, csn, urp, mod_op, replacevals); + else + retVal = entry_delete_present_values_wsi_multi_valued(e, type, vals, csn, urp, mod_op, replacevals); + } + else if (attr_state==ATTRIBUTE_DELETED) + { +#if defined(USE_OLD_UNHASHED) + if (is_type_forbidden(type)) { + retVal = LDAP_SUCCESS; + } else { + retVal= LDAP_NO_SUCH_ATTRIBUTE; + } +#else + retVal= LDAP_NO_SUCH_ATTRIBUTE; +#endif + } + else if (attr_state==ATTRIBUTE_NOTFOUND) + { +#if defined(USE_OLD_UNHASHED) + if (is_type_protected(type) || is_type_forbidden(type)) +#else + if (is_type_protected(type)) +#endif + { + retVal = LDAP_SUCCESS; + } else { + if (!urp) { + LDAPDebug1Arg(LDAP_DEBUG_ARGS, "could not find attribute %s\n", + type); + } + retVal = LDAP_NO_SUCH_ATTRIBUTE; + } + if ((LDAP_MOD_REPLACE == mod_op) && replacevals && replacevals[0]) + { + /* Create a new attribute and set the adcsn */ + Slapi_Attr *a = slapi_attr_new(); + slapi_attr_init(a, type); + attr_set_deletion_csn(a,csn); + entry_add_deleted_attribute_wsi(e, a); + } + } + return retVal; +} +static int +entry_delete_present_values_wsi_single_valued(Slapi_Entry *e, const char *type, struct berval **vals, const CSN *csn, int urp, int mod_op, struct berval **replacevals) +{ + int retVal= LDAP_SUCCESS; + Slapi_Attr *a= NULL; + int attr_state= entry_attr_find_wsi(e, type, &a); + /* The attribute is on the present list, or the deleted list and we're doing URP */ + if ( vals == NULL || vals[0] == NULL ) + { + /* delete the entire attribute */ + LDAPDebug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n", type, 0, 0 ); + attr_set_deletion_csn(a,csn); + if(urp) + { + resolve_attribute_state_single_valued(e, a, attr_state); + /* resolve attr state single valued */ + /* keep_present = check_attr_single_value_is_distingiuished(&a->a_present_values); + if ( !keep_present) { + slapi_valueset_done(&a->a_present_values); + entry_present_attribute_to_deleted_attribute(e, a); + } + */ + } + else + { + slapi_valueset_done(&a->a_present_values); + entry_present_attribute_to_deleted_attribute(e, a); + } + retVal= LDAP_SUCCESS; /* This Operation always succeeds when the attribute is Present */ + } + else + { + /* delete some specific values */ + Slapi_Value **valuestodelete= NULL; + valuearray_init_bervalarray(vals,&valuestodelete); /* JCM SLOW FUNCTION */ + /* Check if the type of the to-be-deleted values has DN syntax + * or not. */ + if (slapi_attr_is_dn_syntax_attr(a)) { + valuearray_dn_normalize_value(valuestodelete); + a->a_flags |= SLAPI_ATTR_FLAG_NORMALIZED_CES; + } + if(urp) + { + Slapi_Value **valuesupdated= NULL; + valueset_update_csn_for_valuearray(&a->a_present_values, a, valuestodelete, CSN_TYPE_VALUE_DELETED, csn, &valuesupdated); + if( valuesupdated && *valuesupdated) + { + attr_set_deletion_csn(a,csn); + } + /* resolve attr state single valued */ + valuearray_free(&valuesupdated); + valueset_update_csn_for_valuearray(&a->a_deleted_values, a, valuestodelete, CSN_TYPE_VALUE_DELETED, csn, &valuesupdated); + valuearray_free(&valuesupdated); + valuearray_update_csn(valuestodelete,CSN_TYPE_VALUE_DELETED,csn); + valueset_add_valuearray_ext(&a->a_deleted_values, valuestodelete, SLAPI_VALUE_FLAG_PASSIN); + slapi_ch_free((void **)&valuestodelete); + resolve_attribute_state_single_valued(e, a, attr_state); + retVal= LDAP_SUCCESS; + } + else + { + Slapi_Value **deletedvalues= NULL; + retVal= valueset_remove_valuearray(&a->a_present_values, a, valuestodelete, 0 /* Do Not Ignore Errors */,&deletedvalues); + if(retVal==LDAP_SUCCESS && deletedvalues != NULL) + { + valuearray_free(&deletedvalues); + /* The attribute is single valued and the value was successful deleted */ + entry_present_attribute_to_deleted_attribute(e, a); + } + else if (retVal != LDAP_SUCCESS) + { + /* Failed + * - Value not found + * - Operations error + */ + if ( retVal==LDAP_OPERATIONS_ERROR ) + { + LDAPDebug( LDAP_DEBUG_ANY, "Possible existing duplicate " + "value for attribute type %s found in " + "entry %s\n", a->a_type, slapi_entry_get_dn_const(e), 0 ); + } + } + valuearray_free(&valuestodelete); + } + } + return( retVal ); +} +static int +entry_delete_present_values_wsi_multi_valued(Slapi_Entry *e, const char *type, struct berval **vals, const CSN *csn, int urp, int mod_op, struct berval **replacevals) +{ + int retVal= LDAP_SUCCESS; + Slapi_Attr *a= NULL; + int attr_state= entry_attr_find_wsi(e, type, &a); /* The attribute is on the present list, or the deleted list and we're doing URP */ if ( vals == NULL || vals[0] == NULL ) { @@ -541,16 +785,19 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval attr_set_deletion_csn(a,csn); if(urp) { - resolve_attribute_state(e, a, attr_state, 1 /* set delete priority */); /* ABSOLVED */ + /* there might be values added or specifically deleted later than + * the current attr delete operation. These values need to be + * preserved, all others can be removed, purging should o the job. + */ + valueset_purge(&a->a_present_values, csn); + valueset_purge(&a->a_deleted_values, csn); + if(valueset_isempty(&a->a_present_values)) + entry_present_attribute_to_deleted_attribute(e, a); } else { - if(!slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE)) - { - /* We don't maintain a deleted value list for single valued attributes */ - valueset_add_valueset(&a->a_deleted_values, &a->a_present_values); /* JCM Would be better to passin the valuestodelete */ - } slapi_valueset_done(&a->a_present_values); + slapi_valueset_done(&a->a_deleted_values); entry_present_attribute_to_deleted_attribute(e, a); } retVal= LDAP_SUCCESS; /* This Operation always succeeds when the attribute is Present */ @@ -558,8 +805,8 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval else { /* delete some specific values */ - Slapi_Value **valuestodelete= NULL; - valuearray_init_bervalarray(vals,&valuestodelete); /* JCM SLOW FUNCTION */ + Slapi_Value **valuestodelete= NULL; + valuearray_init_bervalarray(vals,&valuestodelete); /* JCM SLOW FUNCTION */ /* Check if the type of the to-be-deleted values has DN syntax * or not. */ if (slapi_attr_is_dn_syntax_attr(a)) { @@ -568,47 +815,43 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval } if(urp) { + /* check if values to delete are in present values + * if v in present values and VU-csna_present_values, a, valuestodelete, CSN_TYPE_VALUE_DELETED, csn, &valuesupdated); - /* if we removed the last value, we need to mark the attribute as deleted - the resolve_attribute_state() code will "resurrect" the attribute if - there are present values with a later CSN - otherwise, even though - the value will be updated with a VDCSN which is later than the VUCSN, - the attribute will not be deleted */ - if(slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE) && valuesupdated && - *valuesupdated) - { - attr_set_deletion_csn(a,csn); - } + valueset_update_csn_for_valuearray_ext(&a->a_present_values, a, valuestodelete, CSN_TYPE_VALUE_DELETED, csn, &valuesupdated, 1); + resolve_attribute_state_present_to_deleted(e, a, valuesupdated); valuearray_free(&valuesupdated); - valueset_update_csn_for_valuearray(&a->a_deleted_values, a, valuestodelete, CSN_TYPE_VALUE_DELETED, csn, &valuesupdated); + + valueset_update_csn_for_valuearray_ext(&a->a_deleted_values, a, valuestodelete, CSN_TYPE_VALUE_DELETED, csn, &valuesupdated, 1); + resolve_attribute_state_deleted_to_present(e, a, valuesupdated); valuearray_free(&valuesupdated); + valuearray_update_csn(valuestodelete,CSN_TYPE_VALUE_DELETED,csn); valueset_add_valuearray_ext(&a->a_deleted_values, valuestodelete, SLAPI_VALUE_FLAG_PASSIN); /* all the elements in valuestodelete are passed; * should free valuestodelete only (don't call valuearray_free) * [622023] */ slapi_ch_free((void **)&valuestodelete); - resolve_attribute_state(e, a, attr_state, 0); retVal= LDAP_SUCCESS; } else { + /* find the values to delete in present values, + * update the csns and add to the deleted values + */ Slapi_Value **deletedvalues= NULL; retVal= valueset_remove_valuearray(&a->a_present_values, a, valuestodelete, 0 /* Do Not Ignore Errors */,&deletedvalues); if(retVal==LDAP_SUCCESS && deletedvalues != NULL) { - if(!slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE)) - { - /* We don't maintain a deleted value list for single valued attributes */ - /* Add each deleted value to the deleted set */ - valuearray_update_csn(deletedvalues,CSN_TYPE_VALUE_DELETED,csn); - valueset_add_valuearray_ext(&a->a_deleted_values, deletedvalues, SLAPI_VALUE_FLAG_PASSIN); - slapi_ch_free((void **)&deletedvalues); - } - else { - valuearray_free(&deletedvalues); - } + /* Add each deleted value to the deleted set */ + valuearray_update_csn(deletedvalues,CSN_TYPE_VALUE_DELETED,csn); + valueset_add_valuearray_ext(&a->a_deleted_values, deletedvalues, SLAPI_VALUE_FLAG_PASSIN); + slapi_ch_free((void **)&deletedvalues); if(valueset_isempty(&a->a_present_values)) { /* There are no present values, so move the @@ -619,7 +862,6 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval else if (retVal != LDAP_SUCCESS) { /* Failed - * - Duplicate value * - Value not found * - Operations error */ @@ -633,69 +875,6 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval valuearray_free(&valuestodelete); } } - } - else if (attr_state==ATTRIBUTE_DELETED) - { - /* If the type is in the forbidden attr list (e.g., unhashed password), - * we don't return the reason of the failure to the clients. */ -#if defined(USE_OLD_UNHASHED) - if (is_type_forbidden(type)) { - retVal = LDAP_SUCCESS; - } else { - retVal= LDAP_NO_SUCH_ATTRIBUTE; - } -#else - retVal= LDAP_NO_SUCH_ATTRIBUTE; -#endif - } - else if (attr_state==ATTRIBUTE_NOTFOUND) - { - /* - * If type is in the protected_attrs_all list, we could ignore the - * failure, as the attribute could only exist in the entry in the - * memory when the add/mod operation is done, while the retried entry - * from the db does not contain the attribute. - * So is in the forbidden_attrs list. We don't return the reason - * of the failure. - */ -#if defined(USE_OLD_UNHASHED) - if (is_type_protected(type) || is_type_forbidden(type)) -#else - if (is_type_protected(type)) -#endif - { - retVal = LDAP_SUCCESS; - } else { - if (!urp) { - /* Only warn if not urping */ - LDAPDebug1Arg(LDAP_DEBUG_ARGS, "could not find attribute %s\n", - type); - } - retVal = LDAP_NO_SUCH_ATTRIBUTE; - } - /* NOTE: LDAP says that a MOD REPLACE with no vals of a non-existent - attribute is a no-op - MOD REPLACE with some vals will add the attribute */ - /* if we are doing a replace with actual values, meaning the result - of the mod is that the attribute will have some values, we need to create - a dummy attribute for entry_add_present_values_wsi to use, and set - the deletion csn to the csn of the current operation */ - /* note that if LDAP_MOD_REPLACE == mod_op then vals is NULL - - see entry_replace_present_values_wsi */ - if ((LDAP_MOD_REPLACE == mod_op) && replacevals && replacevals[0]) - { - /* Create a new attribute and set the adcsn */ - Slapi_Attr *a = slapi_attr_new(); - slapi_attr_init(a, type); - attr_set_deletion_csn(a,csn); - /* mark the attribute as deleted - it does not really - exist yet - the code in entry_add_present_values_wsi - will add it back to the present list in the non urp case, - or determine if the attribute needs to be added - or not in the urp case - */ - entry_add_deleted_attribute_wsi(e, a); - } - } return( retVal ); } @@ -825,7 +1004,7 @@ entry_apply_mods_wsi(Slapi_Entry *e, Slapi_Mods *smods, const CSN *csn, int urp) and the csn doesn't already have a subsequence if the csn already has a subsequence, assume it was generated on another replica in the correct order */ - if (urp && (csn_get_subseqnum(csn) == 0)) { + if (csn_get_subseqnum(csn) == 0) { csn_increment_subsequence(&localcsn); } } @@ -1043,87 +1222,54 @@ value_distinguished_at_csn(const Slapi_Entry *e, const Slapi_Attr *original_attr return r; } +/* This call ensures that the value does not contain a deletion_csn which is before the presence_csn or distinguished_csn of the value. */ static void -resolve_attribute_state_multi_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, int delete_priority) +resolve_attribute_state_deleted_to_present(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate) { - int i; + const CSN *vdcsn; + const CSN *vucsn; + const CSN *deletedcsn; const CSN *adcsn= attr_get_deletion_csn(a); - Slapi_ValueSet *vs= valueset_dup(&a->a_present_values); /* JCM This is slow... but otherwise we end up iterating through a changing array */ - Slapi_Value *v; - - /* Loop over the present attribute values */ - i= slapi_valueset_first_value( vs, &v ); - while(v!=NULL) - { - const CSN *vdcsn; - const CSN *vucsn; - const CSN *deletedcsn; - /* This call ensures that the value does not contain a deletion_csn - * which is before the presence_csn or distinguished_csn of the value. - */ - purge_attribute_state_multi_valued(a, v); - vdcsn= value_get_csn(v, CSN_TYPE_VALUE_DELETED); - vucsn= value_get_csn(v, CSN_TYPE_VALUE_UPDATED); - deletedcsn= csn_max(vdcsn, adcsn); - - /* Check if the attribute or value was deleted after the value was - * last updated. If the value update CSN and the deleted CSN are - * the same (meaning they are separate mods from the same exact - * operation), we should only delete the value if delete priority - * is set. Delete priority should only be set when we are deleting - * all value of an attribute. This prevents us from leaving a value - * that was added as a previous mod in the same exact modify - * operation as the subsequent delete.*/ - if((csn_compare(vucsn,deletedcsn)<0) || - (delete_priority && (csn_compare(vucsn,deletedcsn) == 0))) - { - if(!value_distinguished_at_csn(e, a, v, deletedcsn)) + int i; + if ( valuestoupdate != NULL && valuestoupdate[0] != NULL ) { + for (i=0;valuestoupdate[i]!=NULL;++i) { + purge_attribute_state_multi_valued(a, valuestoupdate[i]); + vdcsn= value_get_csn(valuestoupdate[i], CSN_TYPE_VALUE_DELETED); + vucsn= value_get_csn(valuestoupdate[i], CSN_TYPE_VALUE_UPDATED); + deletedcsn= csn_max(vdcsn, adcsn); + if((csn_compare(vucsn,deletedcsn)>=0) || + value_distinguished_at_csn(e, a, valuestoupdate[i], deletedcsn)) { - entry_present_value_to_deleted_value(a,v); + entry_deleted_value_to_present_value(a,valuestoupdate[i]); } + valuestoupdate[i]->v_csnset = NULL; } - i= slapi_valueset_next_value( vs, i, &v ); } - slapi_valueset_free(vs); - - /* Loop over the deleted attribute values */ - vs= valueset_dup(&a->a_deleted_values); /* JCM This is slow... but otherwise we end up iterating through a changing array */ - i= slapi_valueset_first_value( vs, &v ); - while(v!=NULL) - { - const CSN *vdcsn; - const CSN *vucsn; - const CSN *deletedcsn; - /* This call ensures that the value does not contain a deletion_csn which is before the presence_csn or distinguished_csn of the value. */ - purge_attribute_state_multi_valued(a, v); - vdcsn= value_get_csn(v, CSN_TYPE_VALUE_DELETED); - vucsn= value_get_csn(v, CSN_TYPE_VALUE_UPDATED); - deletedcsn= csn_max(vdcsn, adcsn); +} - /* check if the attribute or value was deleted after the value was last updated */ - /* When a replace operation happens, the entry_replace_present_values_wsi() function - * first calls entry_delete_present_values_wsi with vals == NULL to essentially delete - * the attribute and set the deletion csn. If the urp flag is set (urp in this case - * meaning the operation is a replicated op), entry_delete_present_values_wsi will - * call this function which will move the present values to the deleted values - * (see above - delete_priority will be 1) then the below code will move the - * attribute to the deleted list. - * next, entry_replace_present_values_wsi will call entry_add_present_values_wsi - * to add the values provided in the replace operation. We need to be able to - * "resurrect" these deleted values and resurrect the deleted attribute. In the - * replace case, the deletedcsn will be the same as the vucsn of the values that - * should be present values. - */ - if((csn_compare(vucsn,deletedcsn)>0) || - ((delete_priority == 0) && (csn_compare(vucsn,deletedcsn)==0)) || - value_distinguished_at_csn(e, a, v, deletedcsn)) - { - entry_deleted_value_to_present_value(a,v); +static void +resolve_attribute_state_to_present_or_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate, int attribute_state) +{ + const CSN *vdcsn; + const CSN *vucsn; + const CSN *deletedcsn; + const CSN *adcsn= attr_get_deletion_csn(a); + int i; + if ( valuestoupdate != NULL && valuestoupdate[0] != NULL ) { + for (i=0;valuestoupdate[i]!=NULL;++i) { + purge_attribute_state_multi_valued(a, valuestoupdate[i]); + vdcsn= value_get_csn(valuestoupdate[i], CSN_TYPE_VALUE_DELETED); + vucsn= value_get_csn(valuestoupdate[i], CSN_TYPE_VALUE_UPDATED); + deletedcsn= csn_max(vdcsn, adcsn); + if((csn_compare(vucsn,deletedcsn)>=0) || + value_distinguished_at_csn(e, a, valuestoupdate[i], deletedcsn)) + { + slapi_valueset_add_value_ext(&a->a_present_values, valuestoupdate[i], SLAPI_VALUE_FLAG_PASSIN); + } else { + slapi_valueset_add_value_ext(&a->a_deleted_values, valuestoupdate[i], SLAPI_VALUE_FLAG_PASSIN); + } } - i= slapi_valueset_next_value( vs, i, &v ); } - slapi_valueset_free(vs); - if(valueset_isempty(&a->a_present_values)) { if(attribute_state==ATTRIBUTE_PRESENT) @@ -1141,6 +1287,35 @@ resolve_attribute_state_multi_valued(Slapi_Entry *e, Slapi_Attr *a, int attribut } static void +resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate) +{ + const CSN *vdcsn; + const CSN *vucsn; + const CSN *deletedcsn; + const CSN *adcsn= attr_get_deletion_csn(a); + int i; + if ( valuestoupdate != NULL && valuestoupdate[0] != NULL ) { + for (i=0;valuestoupdate[i]!=NULL;++i) { + /* This call ensures that the value does not contain a deletion_csn + * which is before the presence_csn or distinguished_csn of the value. + */ + purge_attribute_state_multi_valued(a, valuestoupdate[i]); + vdcsn= value_get_csn(valuestoupdate[i], CSN_TYPE_VALUE_DELETED); + vucsn= value_get_csn(valuestoupdate[i], CSN_TYPE_VALUE_UPDATED); + deletedcsn= csn_max(vdcsn, adcsn); + if(csn_compare(vucsn,deletedcsn)<0) + { + if(!value_distinguished_at_csn(e, a, valuestoupdate[i], deletedcsn)) + { + entry_present_value_to_deleted_value(a,valuestoupdate[i]); + } + } + valuestoupdate[i]->v_csnset = NULL; + } + } +} + +static void resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state) { Slapi_Value *current_value= NULL; @@ -1292,15 +1467,3 @@ resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribu } } -static void -resolve_attribute_state(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, int delete_priority) -{ - if(slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE)) - { - resolve_attribute_state_single_valued(e,a,attribute_state); - } - else - { - resolve_attribute_state_multi_valued(e,a,attribute_state, delete_priority); - } -} diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index acea92f..43cf245 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -192,6 +192,7 @@ Slapi_ValueSet *valueset_dup(const Slapi_ValueSet *dupee); void valueset_remove_string(const Slapi_Attr *a, Slapi_ValueSet *vs, const char *s); int valueset_replace(Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **vals); void valueset_update_csn_for_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **valuestoupdate, CSNType t, const CSN *csn, Slapi_Value ***valuesupdated); +void valueset_update_csn_for_valuearray_ext(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **valuestoupdate, CSNType t, const CSN *csn, Slapi_Value ***valuesupdated, int csnref_updated); void valueset_set_valuearray_byval(Slapi_ValueSet *vs, Slapi_Value **addvals); void valueset_set_valuearray_passin(Slapi_ValueSet *vs, Slapi_Value **addvals); int valuearray_subtract_bvalues(Slapi_Value **va, struct berval **bvals); diff --git a/ldap/servers/slapd/valueset.c b/ldap/servers/slapd/valueset.c index 6bc3ffa..c041714 100644 --- a/ldap/servers/slapd/valueset.c +++ b/ldap/servers/slapd/valueset.c @@ -1428,6 +1428,11 @@ valueset_replace(Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **valstoreplace) void valueset_update_csn_for_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **valuestoupdate, CSNType t, const CSN *csn, Slapi_Value ***valuesupdated) { + valueset_update_csn_for_valuearray_ext(vs, a, valuestoupdate, t, csn, valuesupdated, 0); +} +void +valueset_update_csn_for_valuearray_ext(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **valuestoupdate, CSNType t, const CSN *csn, Slapi_Value ***valuesupdated, int csnref_updated) +{ if(!valuearray_isempty(valuestoupdate) && !valuearray_isempty(vs->va)) { @@ -1450,6 +1455,8 @@ valueset_update_csn_for_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slap if(rc==LDAP_SUCCESS) { value_update_csn(vs->va[index],t,csn); + if (csnref_updated) + valuestoupdate[i]->v_csnset = value_get_csnset(vs->va[index]); valuearrayfast_add_value_passin(&vaf_valuesupdated,valuestoupdate[i]); valuestoupdate[i] = NULL; } @@ -1465,6 +1472,8 @@ valueset_update_csn_for_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slap if(index!=-1) { value_update_csn(vs->va[index],t,csn); + if (csnref_updated) + valuestoupdate[i]->v_csnset = value_get_csnset(vs->va[index]); valuearrayfast_add_value_passin(&vaf_valuesupdated,valuestoupdate[i]); valuestoupdate[i]= NULL; } -- 1.7.11.7