mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-02-03 20:40:05 -05:00
New modify handler, compares old and new entry and to generate deltas.
Avoids unnecessary rewrites of unchanged attributes.
This commit is contained in:
parent
f77232769c
commit
c3545e6060
1 changed files with 215 additions and 115 deletions
|
|
@ -1325,6 +1325,9 @@ syncrepl_message_to_op(
|
|||
op->orr_modlist = NULL;
|
||||
if ( slap_modrdn2mods( op, &rs ))
|
||||
goto done;
|
||||
/* FIXME: append entryCSN, modifiersName, modifyTimestamp to
|
||||
* modlist here. Should accesslog give these to us in a reqMod?
|
||||
*/
|
||||
rc = op->o_bd->be_modrdn( op, &rs );
|
||||
slap_mods_free( op->orr_modlist, 1 );
|
||||
Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
|
||||
|
|
@ -1523,17 +1526,18 @@ static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
|
|||
* the new ones. This avoids the issue of trying to delete/add a non-leaf
|
||||
* entry.
|
||||
*
|
||||
* We don't try to otherwise distinguish ModDN from Modify; in the case of
|
||||
* a ModDN we will issue both operations on the local database.
|
||||
* We otherwise distinguish ModDN from Modify; in the case of
|
||||
* a ModDN we just use the CSN, modifyTimestamp and modifiersName
|
||||
* operational attributes from the entry, and do a regular ModDN.
|
||||
*/
|
||||
typedef struct dninfo {
|
||||
Entry *new_entry;
|
||||
struct berval dn;
|
||||
struct berval ndn;
|
||||
int renamed; /* Was an existing entry renamed? */
|
||||
int wasChanged; /* are the attributes changed? */
|
||||
int attrs; /* how many attribute types are in the ads list */
|
||||
AttributeDescription **ads;
|
||||
int delOldRDN; /* Was old RDN deleted? */
|
||||
Modifications **modlist; /* the modlist we received */
|
||||
Modifications *mods; /* the modlist we compared */
|
||||
} dninfo;
|
||||
|
||||
static int
|
||||
|
|
@ -1653,6 +1657,7 @@ syncrepl_entry(
|
|||
cb.sc_response = dn_callback;
|
||||
cb.sc_private = &dni;
|
||||
dni.new_entry = entry;
|
||||
dni.modlist = modlist;
|
||||
|
||||
if ( limits_check( op, &rs_search ) == 0 ) {
|
||||
rc = be->be_search( op, &rs_search );
|
||||
|
|
@ -1826,7 +1831,7 @@ retry_add:;
|
|||
op->orr_newSup = NULL;
|
||||
op->orr_nnewSup = NULL;
|
||||
}
|
||||
op->orr_deleteoldrdn = 0;
|
||||
op->orr_deleteoldrdn = dni.delOldRDN;
|
||||
op->orr_modlist = NULL;
|
||||
if (( rc = slap_modrdn2mods( op, &rs_modify ))) {
|
||||
goto done;
|
||||
|
|
@ -1838,6 +1843,34 @@ retry_add:;
|
|||
noldp = op->orr_nnewrdn;
|
||||
ber_dupbv_x( &op->orr_nnewrdn, &noldp, op->o_tmpmemctx );
|
||||
|
||||
/* Setup opattrs too */
|
||||
{
|
||||
AttributeDescription *opattrs[] = {
|
||||
slap_schema.si_ad_entryCSN,
|
||||
slap_schema.si_ad_modifiersName,
|
||||
slap_schema.si_ad_modifyTimestamp,
|
||||
NULL
|
||||
};
|
||||
Modifications *mod, **modtail, **ml;
|
||||
int i;
|
||||
|
||||
for (mod=op->orr_modlist; mod->sml_next; mod=mod->sml_next)
|
||||
;
|
||||
modtail = &mod->sml_next;
|
||||
|
||||
/* pull mod off incoming modlist, append to orr_modlist */
|
||||
for (i=0; opattrs[i]; i++) {
|
||||
for (ml = modlist; *ml; ml = &(*ml)->sml_next)
|
||||
if ( (*ml)->sml_desc == opattrs[i] ) {
|
||||
mod = *ml;
|
||||
*ml = mod->sml_next;
|
||||
mod->sml_next = NULL;
|
||||
*modtail = mod;
|
||||
modtail = &mod->sml_next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = be->be_modrdn( op, &rs_modify );
|
||||
op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );
|
||||
op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );
|
||||
|
|
@ -1846,68 +1879,14 @@ retry_add:;
|
|||
Debug( LDAP_DEBUG_SYNC,
|
||||
"syncrepl_entry: rid %03ld be_modrdn (%d)\n",
|
||||
si->si_rid, rc, 0 );
|
||||
if ( rs_modify.sr_err == LDAP_SUCCESS ) {
|
||||
op->o_req_dn = entry->e_name;
|
||||
op->o_req_ndn = entry->e_nname;
|
||||
} else {
|
||||
goto done;
|
||||
}
|
||||
if ( dni.wasChanged )
|
||||
slap_op_time( &op->o_time, &op->o_tincr );
|
||||
goto done;
|
||||
}
|
||||
if ( dni.wasChanged ) {
|
||||
Modifications *mod, *modhead = NULL;
|
||||
Modifications *modtail = NULL;
|
||||
int i;
|
||||
|
||||
if ( dni.mods ) {
|
||||
op->o_tag = LDAP_REQ_MODIFY;
|
||||
|
||||
assert( *modlist != NULL );
|
||||
|
||||
/* Delete all the old attrs */
|
||||
for ( i = 0; i < dni.attrs; i++ ) {
|
||||
mod = ch_malloc( sizeof( Modifications ) );
|
||||
mod->sml_op = LDAP_MOD_DELETE;
|
||||
mod->sml_flags = 0;
|
||||
mod->sml_desc = dni.ads[i];
|
||||
mod->sml_type = mod->sml_desc->ad_cname;
|
||||
mod->sml_values = NULL;
|
||||
mod->sml_nvalues = NULL;
|
||||
if ( !modhead ) modhead = mod;
|
||||
if ( modtail ) {
|
||||
modtail->sml_next = mod;
|
||||
}
|
||||
modtail = mod;
|
||||
}
|
||||
|
||||
/* Append passed in list to ours */
|
||||
if ( modtail ) {
|
||||
modtail->sml_next = *modlist;
|
||||
*modlist = modhead;
|
||||
} else {
|
||||
mod = *modlist;
|
||||
}
|
||||
|
||||
/* Find end of this list */
|
||||
for ( ; mod != NULL; mod = mod->sml_next ) {
|
||||
modtail = mod;
|
||||
}
|
||||
|
||||
mod = (Modifications *)ch_calloc(1, sizeof(Modifications));
|
||||
mod->sml_op = LDAP_MOD_REPLACE;
|
||||
mod->sml_flags = 0;
|
||||
mod->sml_desc = slap_schema.si_ad_entryUUID;
|
||||
mod->sml_type = mod->sml_desc->ad_cname;
|
||||
ber_dupbv( &uuid_bv, &syncUUID_strrep );
|
||||
ber_bvarray_add( &mod->sml_values, &uuid_bv );
|
||||
ber_dupbv( &uuid_bv, syncUUID );
|
||||
ber_bvarray_add( &mod->sml_nvalues, &uuid_bv );
|
||||
modtail->sml_next = mod;
|
||||
|
||||
op->o_tag = LDAP_REQ_MODIFY;
|
||||
op->orm_modlist = *modlist;
|
||||
op->orm_modlist = dni.mods;
|
||||
|
||||
rc = be->be_modify( op, &rs_modify );
|
||||
slap_mods_free( op->orm_modlist, 1 );
|
||||
Debug( LDAP_DEBUG_SYNC,
|
||||
"syncrepl_entry: rid %03ld be_modify (%d)\n",
|
||||
si->si_rid, rc, 0 );
|
||||
|
|
@ -1957,9 +1936,6 @@ done:
|
|||
slap_sl_free( syncUUID_strrep.bv_val, op->o_tmpmemctx );
|
||||
BER_BVZERO( &syncUUID_strrep );
|
||||
}
|
||||
if ( dni.ads ) {
|
||||
op->o_tmpfree( dni.ads, op->o_tmpmemctx );
|
||||
}
|
||||
if ( !BER_BVISNULL( &dni.ndn ) ) {
|
||||
op->o_tmpfree( dni.ndn.bv_val, op->o_tmpmemctx );
|
||||
}
|
||||
|
|
@ -2352,6 +2328,129 @@ syncrepl_updateCookie(
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
attr_cmp( Operation *op, Attribute *old, Attribute *new,
|
||||
Modifications ***mret, Modifications ***mcur )
|
||||
{
|
||||
int i, j, doadd = 0;
|
||||
Modifications *mod, **modtail;
|
||||
|
||||
modtail = *mret;
|
||||
|
||||
if ( old ) {
|
||||
int n, o, d, a, *adds, *dels;
|
||||
/* count old and new */
|
||||
for ( o=0; old->a_vals[o].bv_val; o++ ) ;
|
||||
for ( n=0; new->a_vals[n].bv_val; n++ ) ;
|
||||
|
||||
adds = op->o_tmpalloc( sizeof(int) * n, op->o_tmpmemctx );
|
||||
dels = op->o_tmpalloc( sizeof(int) * o, op->o_tmpmemctx );
|
||||
d = 0;
|
||||
a = 0;
|
||||
i = 0;
|
||||
j = 0;
|
||||
|
||||
while ( i < o && j < n ) {
|
||||
int k;
|
||||
if ( bvmatch( &old->a_vals[i], &new->a_vals[j] )) {
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
for ( k=j+1; k<n; k++ ) {
|
||||
if ( bvmatch( &old->a_vals[i], &new->a_vals[k] )) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* an old value was deleted */
|
||||
if ( k == n ) {
|
||||
dels[d++] = i++;
|
||||
continue;
|
||||
}
|
||||
for ( k=i+1; k<o; k++ ) {
|
||||
if ( bvmatch( &old->a_vals[k], &new->a_vals[j] )) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( k == o ) {
|
||||
adds[a++] = j++;
|
||||
}
|
||||
}
|
||||
while ( i < o )
|
||||
dels[d++] = i++;
|
||||
while ( j < n )
|
||||
adds[a++] = j++;
|
||||
|
||||
/* all old values were deleted, just use the replace op */
|
||||
if ( d == o ) {
|
||||
i = j-1;
|
||||
} else if ( d ) {
|
||||
/* delete some values */
|
||||
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_values = ch_malloc(( d+1) * sizeof(struct berval));
|
||||
if ( old->a_vals != old->a_nvals )
|
||||
mod->sml_nvalues = ch_malloc(( d+1) * sizeof(struct berval));
|
||||
else
|
||||
mod->sml_nvalues = NULL;
|
||||
for ( i=0; i<d; i++ ) {
|
||||
ber_dupbv( &mod->sml_values[i], &old->a_vals[dels[i]] );
|
||||
if ( mod->sml_nvalues )
|
||||
ber_dupbv( &mod->sml_nvalues[i], &old->a_nvals[dels[i]] );
|
||||
}
|
||||
BER_BVZERO( &mod->sml_values[i] );
|
||||
if ( mod->sml_nvalues )
|
||||
BER_BVZERO( &mod->sml_nvalues[i] );
|
||||
*modtail = mod;
|
||||
modtail = &mod->sml_next;
|
||||
i = j;
|
||||
}
|
||||
op->o_tmpfree( dels, op->o_tmpmemctx );
|
||||
/* some values were added */
|
||||
if ( a && d < o ) {
|
||||
mod = ch_malloc( sizeof( Modifications ) );
|
||||
mod->sml_op = LDAP_MOD_ADD;
|
||||
mod->sml_flags = 0;
|
||||
mod->sml_desc = old->a_desc;
|
||||
mod->sml_type = mod->sml_desc->ad_cname;
|
||||
mod->sml_values = ch_malloc(( a+1) * sizeof(struct berval));
|
||||
if ( old->a_vals != old->a_nvals )
|
||||
mod->sml_nvalues = ch_malloc(( a+1) * sizeof(struct berval));
|
||||
else
|
||||
mod->sml_nvalues = NULL;
|
||||
for ( i=0; i<a; i++ ) {
|
||||
ber_dupbv( &mod->sml_values[i], &new->a_vals[adds[i]] );
|
||||
if ( mod->sml_nvalues )
|
||||
ber_dupbv( &mod->sml_nvalues[i], &new->a_nvals[adds[i]] );
|
||||
}
|
||||
BER_BVZERO( &mod->sml_values[i] );
|
||||
if ( mod->sml_nvalues )
|
||||
BER_BVZERO( &mod->sml_nvalues[i] );
|
||||
*modtail = mod;
|
||||
modtail = &mod->sml_next;
|
||||
i = j;
|
||||
}
|
||||
op->o_tmpfree( adds, op->o_tmpmemctx );
|
||||
} else {
|
||||
/* new attr, just use the new mod */
|
||||
i = 0;
|
||||
j = 1;
|
||||
}
|
||||
/* advance to next element */
|
||||
mod = **mcur;
|
||||
if ( i != j ) {
|
||||
**mcur = mod->sml_next;
|
||||
*modtail = mod;
|
||||
modtail = &mod->sml_next;
|
||||
} else {
|
||||
*mcur = &mod->sml_next;
|
||||
}
|
||||
*mret = modtail;
|
||||
}
|
||||
|
||||
static int
|
||||
dn_callback(
|
||||
Operation* op,
|
||||
|
|
@ -2372,72 +2471,73 @@ dn_callback(
|
|||
* in the provider are always propagated.
|
||||
*/
|
||||
if ( dni->new_entry ) {
|
||||
Modifications **modtail, **ml;
|
||||
Attribute *old, *new;
|
||||
int i;
|
||||
|
||||
/* Did the DN change? Note that we don't explicitly try to
|
||||
* discover if the deleteOldRdn argument applies here. It
|
||||
* would save an unnecessary Modify if we detected it, but
|
||||
* that's a fair amount of trouble to compare the two attr
|
||||
* lists in detail. (Just test normalized DN; we ignore
|
||||
* insignificant changes here.)
|
||||
/* Did the DN change?
|
||||
*/
|
||||
if ( !dn_match( &rs->sr_entry->e_nname,
|
||||
&dni->new_entry->e_nname ) )
|
||||
if ( !dn_match( &rs->sr_entry->e_name,
|
||||
&dni->new_entry->e_name ) )
|
||||
{
|
||||
struct berval oldRDN, oldVal;
|
||||
AttributeDescription *ad = NULL;
|
||||
Attribute *a;
|
||||
|
||||
dni->renamed = 1;
|
||||
/* See if the oldRDN was deleted */
|
||||
dnRdn( &rs->sr_entry->e_nname, &oldRDN );
|
||||
oldVal.bv_val = strchr(oldRDN.bv_val, '=') + 1;
|
||||
oldVal.bv_len = oldRDN.bv_len - ( oldVal.bv_val -
|
||||
oldRDN.bv_val );
|
||||
oldRDN.bv_len -= oldVal.bv_len + 2;
|
||||
slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
|
||||
a = attr_find( dni->new_entry->e_attrs, ad );
|
||||
if ( !a || value_find_ex( ad,
|
||||
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
|
||||
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
|
||||
SLAP_MR_VALUE_OF_SYNTAX, a->a_nvals,
|
||||
&oldVal, op->o_tmpmemctx ) != LDAP_SUCCESS )
|
||||
{
|
||||
dni->delOldRDN = 1;
|
||||
}
|
||||
/* OK, this was just a modDN, we're done */
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
for ( i = 0, old = rs->sr_entry->e_attrs;
|
||||
old;
|
||||
i++, old = old->a_next )
|
||||
;
|
||||
|
||||
dni->attrs = i;
|
||||
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, we signal a change. Otherwise we test
|
||||
* all the values...
|
||||
* 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;
|
||||
old = old->a_next, new = new->a_next )
|
||||
old && new; )
|
||||
{
|
||||
if ( old->a_desc != new->a_desc ) {
|
||||
dni->wasChanged = 1;
|
||||
break;
|
||||
}
|
||||
for ( i = 0; ; i++ ) {
|
||||
int nold, nnew;
|
||||
nold = BER_BVISNULL( &old->a_vals[i] );
|
||||
nnew = BER_BVISNULL( &new->a_vals[i] );
|
||||
/* If both are empty, stop looking */
|
||||
if ( nold && nnew ) {
|
||||
break;
|
||||
}
|
||||
/* If they are different, stop looking */
|
||||
if ( nold != nnew ) {
|
||||
dni->wasChanged = 1;
|
||||
break;
|
||||
}
|
||||
if ( ber_bvcmp( &old->a_vals[i], &new->a_vals[i] )) {
|
||||
dni->wasChanged = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( dni->wasChanged ) break;
|
||||
}
|
||||
if ( dni->wasChanged ) {
|
||||
dni->ads = op->o_tmpalloc( dni->attrs *
|
||||
sizeof(AttributeDescription *), op->o_tmpmemctx );
|
||||
i = 0;
|
||||
for ( old = rs->sr_entry->e_attrs; old; old = old->a_next ) {
|
||||
dni->ads[i] = old->a_desc;
|
||||
i++;
|
||||
/* Delete old attr, force into new order */
|
||||
Modifications *mod;
|
||||
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_values = NULL;
|
||||
mod->sml_nvalues = NULL;
|
||||
*modtail = mod;
|
||||
modtail = &mod->sml_next;
|
||||
|
||||
old = old->a_next;
|
||||
continue;
|
||||
}
|
||||
attr_cmp( op, old, new, &modtail, &ml );
|
||||
new = new->a_next;
|
||||
old = old->a_next;
|
||||
}
|
||||
*modtail = *ml;
|
||||
*ml = NULL;
|
||||
}
|
||||
}
|
||||
} else if ( rs->sr_type == REP_RESULT ) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue