andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From 3aac2e421bb6c2543b2ff2795664ba50a7ceeec9 Mon Sep 17 00:00:00 2001
dc8c34
From: Rich Megginson <rmeggins@redhat.com>
dc8c34
Date: Wed, 17 Jul 2013 17:51:36 -0600
dc8c34
Subject: [PATCH 80/99] Ticket #47424 - Replication problem with add-delete
dc8c34
 requests on single-valued attributes
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/47424
dc8c34
Reviewed by: lkrispenz (Thanks!)
dc8c34
Branch: 389-ds-base-1.2.11
dc8c34
Fix Description: Change the single master resolve attr code to handle the
dc8c34
specific case of doing
dc8c34
add: newvalue
dc8c34
delete: oldvalue
dc8c34
Had to add a new API function - csn_compare_ext - to be able to compare CSNs
dc8c34
without the subsequence number.
dc8c34
Platforms tested: RHEL6 x86_64
dc8c34
Flag Day: no
dc8c34
Doc impact: no
dc8c34
(cherry picked from commit bf53a29af973648c520b005ad37f7a83db4b905b)
dc8c34
---
dc8c34
 ldap/servers/slapd/csn.c           |  12 +++-
dc8c34
 ldap/servers/slapd/entrywsi.c      | 122 +++++++++++++++++++++----------------
dc8c34
 ldap/servers/slapd/slapi-private.h |   2 +
dc8c34
 3 files changed, 83 insertions(+), 53 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/slapd/csn.c b/ldap/servers/slapd/csn.c
dc8c34
index 9fb5b4a..5c31689 100644
dc8c34
--- a/ldap/servers/slapd/csn.c
dc8c34
+++ b/ldap/servers/slapd/csn.c
dc8c34
@@ -298,7 +298,7 @@ csn_as_attr_option_string(CSNType t,const CSN *csn,char *ss)
dc8c34
 }
dc8c34
 
dc8c34
 int 
dc8c34
-csn_compare(const CSN *csn1, const CSN *csn2)
dc8c34
+csn_compare_ext(const CSN *csn1, const CSN *csn2, unsigned int flags)
dc8c34
 {
dc8c34
     PRInt32 retVal;
dc8c34
 	if(csn1!=NULL && csn2!=NULL)
dc8c34
@@ -321,7 +321,7 @@ csn_compare(const CSN *csn1, const CSN *csn2)
dc8c34
                     retVal = -1;
dc8c34
                 else if (csn1->rid > csn2->rid)
dc8c34
                     retVal = 1;
dc8c34
-                else
dc8c34
+                else if (!(flags & CSN_COMPARE_SKIP_SUBSEQ))
dc8c34
                 {
dc8c34
                     if (csn1->subseqnum < csn2->subseqnum)
dc8c34
                         retVal = -1;
dc8c34
@@ -330,6 +330,8 @@ csn_compare(const CSN *csn1, const CSN *csn2)
dc8c34
                     else
dc8c34
                         retVal = 0;
dc8c34
                 }
dc8c34
+                else
dc8c34
+                    retVal = 0;
dc8c34
             }
dc8c34
         }
dc8c34
 		
dc8c34
@@ -350,6 +352,12 @@ csn_compare(const CSN *csn1, const CSN *csn2)
dc8c34
     return(retVal);
dc8c34
 }
dc8c34
 
dc8c34
+int
dc8c34
+csn_compare(const CSN *csn1, const CSN *csn2)
dc8c34
+{
dc8c34
+	return csn_compare_ext(csn1, csn2, 0);
dc8c34
+}
dc8c34
+
dc8c34
 time_t csn_time_difference(const CSN *csn1, const CSN *csn2)
dc8c34
 {
dc8c34
 	return csn_get_time(csn1) - csn_get_time(csn2);
dc8c34
diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c
dc8c34
index 971e9e3..6c37f45 100644
dc8c34
--- a/ldap/servers/slapd/entrywsi.c
dc8c34
+++ b/ldap/servers/slapd/entrywsi.c
dc8c34
@@ -423,8 +423,8 @@ static int
dc8c34
 entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags)
dc8c34
 {
dc8c34
 	int retVal= LDAP_SUCCESS;
dc8c34
-    Slapi_Value **valuestoadd = NULL;
dc8c34
-    valuearray_init_bervalarray(bervals,&valuestoadd); /* JCM SLOW FUNCTION */
dc8c34
+	Slapi_Value **valuestoadd = NULL;
dc8c34
+	valuearray_init_bervalarray(bervals,&valuestoadd); /* JCM SLOW FUNCTION */
dc8c34
 	if(!valuearray_isempty(valuestoadd))
dc8c34
 	{
dc8c34
 		Slapi_Attr *a= NULL;
dc8c34
@@ -437,7 +437,7 @@ entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **b
dc8c34
 			slapi_attr_init(a, type);
dc8c34
 			attrlist_add(&e->e_attrs, a);
dc8c34
 		}
dc8c34
-        a_flags_orig = a->a_flags;
dc8c34
+		a_flags_orig = a->a_flags;
dc8c34
 		a->a_flags |= flags;
dc8c34
 		/* Check if the type of the to-be-added values has DN syntax or not. */
dc8c34
 		if (slapi_attr_is_dn_syntax_attr(a)) {
dc8c34
@@ -558,8 +558,8 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval
dc8c34
 		else
dc8c34
 		{
dc8c34
 			/* delete some specific values */
dc8c34
-		    Slapi_Value **valuestodelete= NULL;
dc8c34
-		    valuearray_init_bervalarray(vals,&valuestodelete); /* JCM SLOW FUNCTION */
dc8c34
+			Slapi_Value **valuestodelete= NULL;
dc8c34
+			valuearray_init_bervalarray(vals,&valuestodelete); /* JCM SLOW FUNCTION */
dc8c34
 			/* Check if the type of the to-be-deleted values has DN syntax 
dc8c34
 			 * or not. */
dc8c34
 			if (slapi_attr_is_dn_syntax_attr(a)) {
dc8c34
@@ -575,8 +575,7 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval
dc8c34
 				   there are present values with a later CSN - otherwise, even though
dc8c34
 				   the value will be updated with a VDCSN which is later than the VUCSN,
dc8c34
 				   the attribute will not be deleted */
dc8c34
-				if(slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE) && valuesupdated &&
dc8c34
-				   *valuesupdated)
dc8c34
+				if(slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE) && valueset_isempty(&a->a_present_values))
dc8c34
 				{
dc8c34
 					attr_set_deletion_csn(a,csn);			
dc8c34
 				}
dc8c34
@@ -626,8 +625,8 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval
dc8c34
 					if ( retVal==LDAP_OPERATIONS_ERROR )
dc8c34
 					{
dc8c34
 						LDAPDebug( LDAP_DEBUG_ANY, "Possible existing duplicate "
dc8c34
-							"value for attribute type %s found in "
dc8c34
-							"entry %s\n", a->a_type, slapi_entry_get_dn_const(e), 0 );
dc8c34
+						           "value for attribute type %s found in "
dc8c34
+						           "entry %s\n", a->a_type, slapi_entry_get_dn_const(e), 0 );
dc8c34
 					}
dc8c34
 				}
dc8c34
 				valuearray_free(&valuestodelete);
dc8c34
@@ -683,7 +682,7 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval
dc8c34
 			   will add it back to the present list in the non urp case,
dc8c34
 			   or determine if the attribute needs to be added
dc8c34
 			   or not in the urp case
dc8c34
-			*/
dc8c34
+			 */
dc8c34
 			entry_add_deleted_attribute_wsi(e, a);
dc8c34
 		}
dc8c34
 	}
dc8c34
@@ -1103,6 +1102,7 @@ resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribu
dc8c34
 	Slapi_Value *new_value= NULL;
dc8c34
 	const CSN *current_value_vucsn;
dc8c34
 	const CSN *pending_value_vucsn;
dc8c34
+	const CSN *pending_value_vdcsn;
dc8c34
 	const CSN *adcsn;
dc8c34
 	int i;
dc8c34
 
dc8c34
@@ -1116,27 +1116,47 @@ resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribu
dc8c34
 		slapi_attr_next_value(a,i,&new_value);
dc8c34
 	}
dc8c34
 	attr_first_deleted_value(a,&pending_value);
dc8c34
-
dc8c34
 	/* purge_attribute_state_single_valued */
dc8c34
 	adcsn= attr_get_deletion_csn(a);
dc8c34
 	current_value_vucsn= value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
dc8c34
 	pending_value_vucsn= value_get_csn(pending_value, CSN_TYPE_VALUE_UPDATED);
dc8c34
-    if((pending_value!=NULL && (csn_compare(adcsn, pending_value_vucsn)<0)) || 
dc8c34
-        (pending_value==NULL && (csn_compare(adcsn, current_value_vucsn)<0)))
dc8c34
+	pending_value_vdcsn= value_get_csn(pending_value, CSN_TYPE_VALUE_DELETED);
dc8c34
+	if((pending_value!=NULL && (csn_compare(adcsn, pending_value_vucsn)<0)) ||
dc8c34
+	   (pending_value==NULL && (csn_compare(adcsn, current_value_vucsn)<0)))
dc8c34
 	{
dc8c34
 		attr_set_deletion_csn(a,NULL);
dc8c34
 		adcsn= NULL;
dc8c34
-    }
dc8c34
+	}
dc8c34
 
dc8c34
-	if(new_value==NULL)
dc8c34
+	/* in the case of the following:
dc8c34
+	 * add: value2
dc8c34
+	 * delete: value1
dc8c34
+	 * we will have current_value with VUCSN CSN1
dc8c34
+	 * and pending_value with VDCSN CSN2
dc8c34
+	 * and new_value == NULL
dc8c34
+	 * current_value != pending_value
dc8c34
+	 * and
dc8c34
+	 * VUCSN == VDCSN (ignoring subseq)
dc8c34
+	 * even though value1.VDCSN > value2.VUCSN
dc8c34
+	 * value2 should still win because the value is _different_
dc8c34
+	 */
dc8c34
+	if (current_value && pending_value && !new_value && !adcsn &&
dc8c34
+	    (0 != slapi_value_compare(a, current_value, pending_value)) &&
dc8c34
+	    (0 == csn_compare_ext(current_value_vucsn, pending_value_vdcsn, CSN_COMPARE_SKIP_SUBSEQ)))
dc8c34
 	{
dc8c34
-        /* check if the pending value should become the current value */ 
dc8c34
-        if(pending_value!=NULL)
dc8c34
+		/* just remove the deleted value */
dc8c34
+		entry_deleted_value_to_zapped_value(a,pending_value);
dc8c34
+		pending_value = NULL;
dc8c34
+	}
dc8c34
+	else if(new_value==NULL)
dc8c34
+	{
dc8c34
+		/* check if the pending value should become the current value */
dc8c34
+		if(pending_value!=NULL)
dc8c34
 		{
dc8c34
 			if(!value_distinguished_at_csn(e,a,current_value,pending_value_vucsn))
dc8c34
 			{
dc8c34
-	            /* attribute.current_value = attribute.pending_value; */
dc8c34
-	            /* attribute.pending_value = NULL; */
dc8c34
+				/* attribute.current_value = attribute.pending_value; */
dc8c34
+				/* attribute.pending_value = NULL; */
dc8c34
 				entry_present_value_to_zapped_value(a,current_value);
dc8c34
 				entry_deleted_value_to_present_value(a,pending_value);
dc8c34
 				current_value= pending_value;
dc8c34
@@ -1145,12 +1165,12 @@ resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribu
dc8c34
 				pending_value_vucsn= NULL;
dc8c34
 			}
dc8c34
 		}
dc8c34
-        /* check if the current value should be deleted */ 
dc8c34
-        if(current_value!=NULL)
dc8c34
+		/* check if the current value should be deleted */
dc8c34
+		if(current_value!=NULL)
dc8c34
 		{
dc8c34
 			if(csn_compare(adcsn,current_value_vucsn)>0) /* check if the attribute was deleted after the value was last updated */
dc8c34
 			{
dc8c34
-	            if(!value_distinguished_at_csn(e,a,current_value,current_value_vucsn))
dc8c34
+				if(!value_distinguished_at_csn(e,a,current_value,current_value_vucsn))
dc8c34
 				{
dc8c34
 					entry_present_value_to_zapped_value(a,current_value);
dc8c34
 					current_value= NULL;
dc8c34
@@ -1162,17 +1182,17 @@ resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribu
dc8c34
 	else /* addition of a new value */ 
dc8c34
 	{
dc8c34
 		const CSN *new_value_vucsn= value_get_csn(new_value,CSN_TYPE_VALUE_UPDATED);
dc8c34
-        if(csn_compare(new_value_vucsn,current_value_vucsn)<0)
dc8c34
+		if(csn_compare(new_value_vucsn,current_value_vucsn)<0)
dc8c34
 		{
dc8c34
-            /*
dc8c34
-             * if the new value was distinguished at the time the current value was added 
dc8c34
-             * then the new value should become current
dc8c34
-             */ 
dc8c34
-            if(value_distinguished_at_csn(e,a,new_value,current_value_vucsn))
dc8c34
+			/*
dc8c34
+			 * if the new value was distinguished at the time the current value was added
dc8c34
+			 * then the new value should become current
dc8c34
+			 */
dc8c34
+			if(value_distinguished_at_csn(e,a,new_value,current_value_vucsn))
dc8c34
 			{
dc8c34
-                /* attribute.pending_value = attribute.current_value  */
dc8c34
-                /* attribute.current_value = new_value  */
dc8c34
-                if(pending_value==NULL)
dc8c34
+				/* attribute.pending_value = attribute.current_value  */
dc8c34
+				/* attribute.current_value = new_value  */
dc8c34
+				if(pending_value==NULL)
dc8c34
 				{
dc8c34
 					entry_present_value_to_deleted_value(a,current_value);
dc8c34
 				}
dc8c34
@@ -1188,63 +1208,63 @@ resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribu
dc8c34
 			}
dc8c34
 			else
dc8c34
 			{
dc8c34
-                /* new_value= NULL */
dc8c34
+				/* new_value= NULL */
dc8c34
 				entry_present_value_to_zapped_value(a, new_value);
dc8c34
 				new_value= NULL;
dc8c34
 			}
dc8c34
 		}
dc8c34
-        else    /* new value is after the current value */ 
dc8c34
+		else    /* new value is after the current value */
dc8c34
 		{
dc8c34
-            if(!value_distinguished_at_csn(e, a, current_value, new_value_vucsn))
dc8c34
+			if(!value_distinguished_at_csn(e, a, current_value, new_value_vucsn))
dc8c34
 			{
dc8c34
-                /* attribute.current_value = new_value */
dc8c34
+				/* attribute.current_value = new_value */
dc8c34
 				entry_present_value_to_zapped_value(a, current_value);
dc8c34
 				current_value= new_value;
dc8c34
 				new_value= NULL;
dc8c34
 				current_value_vucsn= new_value_vucsn;
dc8c34
 			}
dc8c34
-            else /* value is distinguished - check if we should replace the current pending value */ 
dc8c34
+			else /* value is distinguished - check if we should replace the current pending value */
dc8c34
 			{
dc8c34
-                if(csn_compare(new_value_vucsn, pending_value_vucsn)>0)
dc8c34
+				if(csn_compare(new_value_vucsn, pending_value_vucsn)>0)
dc8c34
 				{
dc8c34
-                    /* attribute.pending_value = new_value */
dc8c34
+					/* attribute.pending_value = new_value */
dc8c34
 					entry_deleted_value_to_zapped_value(a,pending_value);
dc8c34
 					entry_present_value_to_deleted_value(a,new_value);
dc8c34
 					pending_value= new_value;
dc8c34
 					new_value= NULL;
dc8c34
 					pending_value_vucsn= new_value_vucsn;
dc8c34
-                } 
dc8c34
-            } 
dc8c34
-        } 
dc8c34
-    } 
dc8c34
+				}
dc8c34
+			}
dc8c34
+		}
dc8c34
+	}
dc8c34
 
dc8c34
-    /*
dc8c34
-     * This call ensures that the attribute does not have a pending_value
dc8c34
+	/*
dc8c34
+	 * This call ensures that the attribute does not have a pending_value
dc8c34
 	 * or a deletion_csn that is earlier than the current_value.
dc8c34
 	 */ 
dc8c34
 	/* purge_attribute_state_single_valued */
dc8c34
-    if((pending_value!=NULL && (csn_compare(adcsn, pending_value_vucsn)<0)) || 
dc8c34
-        (pending_value==NULL && (csn_compare(adcsn, current_value_vucsn)<0)))
dc8c34
+	if((pending_value!=NULL && (csn_compare(adcsn, pending_value_vucsn)<0)) ||
dc8c34
+	   (pending_value==NULL && (csn_compare(adcsn, current_value_vucsn)<0)))
dc8c34
 	{
dc8c34
 		attr_set_deletion_csn(a,NULL);
dc8c34
 		adcsn= NULL;
dc8c34
-    } 
dc8c34
+	}
dc8c34
 
dc8c34
-    /* set attribute state */ 
dc8c34
-    if(current_value==NULL)
dc8c34
+	/* set attribute state */
dc8c34
+	if(current_value==NULL)
dc8c34
 	{
dc8c34
 		if(attribute_state==ATTRIBUTE_PRESENT)
dc8c34
 		{
dc8c34
 			entry_present_attribute_to_deleted_attribute(e, a);
dc8c34
 		}
dc8c34
 	}
dc8c34
-    else 
dc8c34
+	else
dc8c34
 	{
dc8c34
 		if(attribute_state==ATTRIBUTE_DELETED)
dc8c34
 		{
dc8c34
 			entry_deleted_attribute_to_present_attribute(e, a);
dc8c34
 		}
dc8c34
-    }
dc8c34
+	}
dc8c34
 }
dc8c34
 
dc8c34
 static void
dc8c34
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
dc8c34
index ddeac62..1efbc8b 100644
dc8c34
--- a/ldap/servers/slapd/slapi-private.h
dc8c34
+++ b/ldap/servers/slapd/slapi-private.h
dc8c34
@@ -196,6 +196,8 @@ PRUint16 csn_get_seqnum(const CSN *csn);
dc8c34
 PRUint16 csn_get_subseqnum(const CSN *csn);
dc8c34
 char *csn_as_string(const CSN *csn, PRBool replicaIdOrder, char *ss); /* WARNING: ss must be CSN_STRSIZE bytes, or NULL. */
dc8c34
 int csn_compare(const CSN *csn1, const CSN *csn2);
dc8c34
+int csn_compare_ext(const CSN *csn1, const CSN *csn2, unsigned int flags);
dc8c34
+#define CSN_COMPARE_SKIP_SUBSEQ 0x1
dc8c34
 time_t csn_time_difference(const CSN *csn1, const CSN *csn2);
dc8c34
 size_t csn_string_size();
dc8c34
 char *csn_as_attr_option_string(CSNType t,const CSN *csn,char *ss);
dc8c34
-- 
dc8c34
1.8.1.4
dc8c34