From 0132ea425d919d12ee17105993530383d565a988 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 17 Aug 2009 11:58:47 +0000 Subject: [PATCH] ITS#6152 add syncrepl_diff_entry() --- servers/slapd/proto-slap.h | 3 + servers/slapd/syncrepl.c | 159 ++++++++++++++++++++----------------- 2 files changed, 90 insertions(+), 72 deletions(-) diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 48ba6cf4c3..f657d001d7 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -1776,6 +1776,9 @@ LDAP_SLAPD_F (Filter *) str2filter_x LDAP_P(( Operation *op, const char *str )); LDAP_SLAPD_F (int) syncrepl_add_glue LDAP_P(( Operation*, Entry* )); +LDAP_SLAPD_F (void) syncrepl_diff_entry LDAP_P(( + Operation *op, Attribute *old, Attribute *new, + Modifications **mods, Modifications **ml, int is_ctx )); LDAP_SLAPD_F (void) syncinfo_free LDAP_P(( struct syncinfo_s *, int all )); /* syntax.c */ diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index 35e431f6dd..d2d2dbcb41 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -3088,6 +3088,10 @@ syncrepl_updateCookie( return rc; } +/* Compare the attribute from the old entry to the one in the new + * entry. The Modifications from the new entry will either be left + * in place, or changed to an Add or Delete as needed. + */ static void attr_cmp( Operation *op, Attribute *old, Attribute *new, Modifications ***mret, Modifications ***mcur ) @@ -3231,6 +3235,86 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new, *mret = modtail; } +/* Generate a set of modifications to change the old entry into the + * new one. On input ml is a list of modifications equivalent to + * the new entry. It will be massaged and the result will be stored + * in mods. + */ +void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new, + Modifications **mods, Modifications **ml, int is_ctx) +{ + Modifications **modtail = mods; + + /* We assume that attributes are saved in the same order + * in the remote and local databases. So if we walk through + * the attributeDescriptions one by one they should match in + * lock step. If not, look for an add or delete. + */ + while ( old && new ) + { + /* If we've seen this before, use its mod now */ + if ( new->a_flags & SLAP_ATTR_IXADD ) { + attr_cmp( op, NULL, new, &modtail, &ml ); + new = new->a_next; + continue; + } + /* Skip contextCSN */ + if ( is_ctx && old->a_desc == + slap_schema.si_ad_contextCSN ) { + old = old->a_next; + continue; + } + + if ( old->a_desc != new->a_desc ) { + Modifications *mod; + Attribute *tmp; + + /* If it's just been re-added later, + * remember that we've seen it. + */ + tmp = attr_find( new, old->a_desc ); + if ( tmp ) { + tmp->a_flags |= SLAP_ATTR_IXADD; + } else { + /* If it's a new attribute, pull it in. + */ + tmp = attr_find( old, new->a_desc ); + if ( !tmp ) { + attr_cmp( op, NULL, new, &modtail, &ml ); + new = new->a_next; + continue; + } + /* Delete old attr */ + mod = ch_malloc( sizeof( Modifications ) ); + mod->sml_op = LDAP_MOD_DELETE; + mod->sml_flags = 0; + mod->sml_desc = old->a_desc; + mod->sml_type = mod->sml_desc->ad_cname; + mod->sml_numvals = 0; + mod->sml_values = NULL; + mod->sml_nvalues = NULL; + *modtail = mod; + modtail = &mod->sml_next; + } + old = old->a_next; + continue; + } + /* kludge - always update modifiersName so that it + * stays co-located with the other mod opattrs. But only + * if we know there are other valid mods. + */ + if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName || + old->a_desc == slap_schema.si_ad_modifyTimestamp )) + attr_cmp( op, NULL, new, &modtail, &ml ); + else + attr_cmp( op, old, new, &modtail, &ml ); + new = new->a_next; + old = old->a_next; + } + *modtail = *ml; + *ml = NULL; +} + static int dn_callback( Operation* op, @@ -3351,78 +3435,9 @@ dn_callback( */ } - modtail = &dni->mods; - ml = dni->modlist; - - /* We assume that attributes are saved in the same order - * in the remote and local databases. So if we walk through - * the attributeDescriptions one by one they should match in - * lock step. If not, look for an add or delete. - */ - for ( old = rs->sr_entry->e_attrs, new = dni->new_entry->e_attrs; - old && new; ) - { - /* If we've seen this before, use its mod now */ - if ( new->a_flags & SLAP_ATTR_IXADD ) { - attr_cmp( op, NULL, new, &modtail, &ml ); - new = new->a_next; - continue; - } - /* Skip contextCSN */ - if ( is_ctx && old->a_desc == - slap_schema.si_ad_contextCSN ) { - old = old->a_next; - continue; - } - - if ( old->a_desc != new->a_desc ) { - Modifications *mod; - Attribute *tmp; - - /* If it's just been re-added later, - * remember that we've seen it. - */ - tmp = attr_find( new, old->a_desc ); - if ( tmp ) { - tmp->a_flags |= SLAP_ATTR_IXADD; - } else { - /* If it's a new attribute, pull it in. - */ - tmp = attr_find( old, new->a_desc ); - if ( !tmp ) { - attr_cmp( op, NULL, new, &modtail, &ml ); - new = new->a_next; - continue; - } - /* Delete old attr */ - mod = ch_malloc( sizeof( Modifications ) ); - mod->sml_op = LDAP_MOD_DELETE; - mod->sml_flags = 0; - mod->sml_desc = old->a_desc; - mod->sml_type = mod->sml_desc->ad_cname; - mod->sml_numvals = 0; - mod->sml_values = NULL; - mod->sml_nvalues = NULL; - *modtail = mod; - modtail = &mod->sml_next; - } - old = old->a_next; - continue; - } - /* kludge - always update modifiersName so that it - * stays co-located with the other mod opattrs. But only - * if we know there are other valid mods. - */ - if ( dni->mods && ( old->a_desc == slap_schema.si_ad_modifiersName || - old->a_desc == slap_schema.si_ad_modifyTimestamp )) - attr_cmp( op, NULL, new, &modtail, &ml ); - else - attr_cmp( op, old, new, &modtail, &ml ); - new = new->a_next; - old = old->a_next; - } - *modtail = *ml; - *ml = NULL; + syncrepl_diff_entry( op, rs->sr_entry->e_attrs, + dni->new_entry->e_attrs, &dni->mods, dni->modlist, + is_ctx ); } } } else if ( rs->sr_type == REP_RESULT ) { -- 2.39.5