]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/syncrepl.c
Partial revert of f30269f5d2e4bb5ee7486fe6542078d1b59dba6d
[openldap] / servers / slapd / syncrepl.c
index abfa3551a375ac4e62aafaa02cd49a68148a7f6f..39382881a1f2109a1edf60e4ae4e1b6a989576ca 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2003-2011 The OpenLDAP Foundation.
+ * Copyright 2003-2012 The OpenLDAP Foundation.
  * Portions Copyright 2003 by IBM Corporation.
  * Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
  * All rights reserved.
@@ -823,7 +823,7 @@ do_syncrep2(
 
        slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
 
-       if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
+       if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && si->si_refreshDone ) {
                tout_p = &tout;
        } else {
                tout_p = NULL;
@@ -1241,6 +1241,9 @@ do_syncrep2(
                                                si->si_refreshDone = 1;
                                        }
                                        ber_scanf( ber, /*"{"*/ "}" );
+                                       if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
+                                               si->si_refreshDone )
+                                               tout_p = &tout;
                                        break;
                                case LDAP_TAG_SYNC_ID_SET:
                                        Debug( LDAP_DEBUG_SYNC,
@@ -1789,28 +1792,31 @@ typedef struct OpExtraSync {
 /* Copy the original modlist, split Replace ops into Delete/Add,
  * and drop mod opattrs since this modification is in the past.
  */
-static Modifications *mods_dup( Operation *op, Modifications *modlist )
+static Modifications *mods_dup( Operation *op, Modifications *modlist, int match )
 {
        Modifications *mod, *modnew = NULL, *modtail = NULL;
        int size;
        for ( ; modlist; modlist = modlist->sml_next ) {
-               if ( modlist->sml_desc == slap_schema.si_ad_modifiersName ||
-                       modlist->sml_desc == slap_schema.si_ad_modifyTimestamp ||
-                       modlist->sml_desc == slap_schema.si_ad_entryCSN )
-                       continue;
-               if ( modlist->sml_op == LDAP_MOD_REPLACE ) {
-                       mod = op->o_tmpalloc( sizeof(Modifications), op->o_tmpmemctx );
-                       mod->sml_desc = modlist->sml_desc;
-                       mod->sml_values = NULL;
-                       mod->sml_nvalues = NULL;
-                       mod->sml_op = LDAP_MOD_DELETE;
-                       mod->sml_numvals = 0;
-                       mod->sml_flags = 0;
-                       if ( !modnew )
-                               modnew = mod;
-                       if ( modtail )
-                               modtail->sml_next = mod;
-                       modtail = mod;
+               /* older ops */
+               if ( match < 0 ) {
+                       if ( modlist->sml_desc == slap_schema.si_ad_modifiersName ||
+                               modlist->sml_desc == slap_schema.si_ad_modifyTimestamp ||
+                               modlist->sml_desc == slap_schema.si_ad_entryCSN )
+                               continue;
+                       if ( modlist->sml_op == LDAP_MOD_REPLACE ) {
+                               mod = op->o_tmpalloc( sizeof(Modifications), op->o_tmpmemctx );
+                               mod->sml_desc = modlist->sml_desc;
+                               mod->sml_values = NULL;
+                               mod->sml_nvalues = NULL;
+                               mod->sml_op = LDAP_MOD_DELETE;
+                               mod->sml_numvals = 0;
+                               mod->sml_flags = 0;
+                               if ( !modnew )
+                                       modnew = mod;
+                               if ( modtail )
+                                       modtail->sml_next = mod;
+                               modtail = mod;
+                       }
                }
                if ( modlist->sml_numvals ) {
                        size = (modlist->sml_numvals+1) * sizeof(struct berval);
@@ -1833,13 +1839,20 @@ static Modifications *mods_dup( Operation *op, Modifications *modlist )
                        mod->sml_values = (BerVarray)(mod+1);
                        for (i=0; i<mod->sml_numvals; i++)
                                mod->sml_values[i] = modlist->sml_values[i];
+                       BER_BVZERO(&mod->sml_values[i]);
                        if ( modlist->sml_nvalues ) {
                                mod->sml_nvalues = mod->sml_values + mod->sml_numvals + 1;
                                for (i=0; i<mod->sml_numvals; i++)
                                        mod->sml_nvalues[i] = modlist->sml_nvalues[i];
+                               BER_BVZERO(&mod->sml_nvalues[i]);
+                       } else {
+                               mod->sml_nvalues = NULL;
                        }
+               } else {
+                       mod->sml_values = NULL;
+                       mod->sml_nvalues = NULL;
                }
-               if ( modlist->sml_op == LDAP_MOD_REPLACE )
+               if ( match < 0 && modlist->sml_op == LDAP_MOD_REPLACE )
                        mod->sml_op = LDAP_MOD_ADD;
                else
                        mod->sml_op = modlist->sml_op;
@@ -1875,6 +1888,10 @@ compare_vals( Modifications *m1, Modifications *m2 )
                                        if ( m1->sml_nvalues )
                                                m1->sml_nvalues[k] = m1->sml_nvalues[k+1];
                                }
+                               BER_BVZERO(&m1->sml_values[k]);
+                               if ( m1->sml_nvalues ) {
+                                       BER_BVZERO(&m1->sml_nvalues[k]);
+                               }
                                m1->sml_numvals--;
                                i--;
                        }
@@ -1961,15 +1978,14 @@ syncrepl_modify_cb( Operation *op, SlapReply *rs )
        modify_ctxt *mx = sc->sc_private;
        Modifications *ml;
 
-       op->o_callback = sc->sc_next;
-       op->o_tmpfree( sc, op->o_tmpmemctx );
-
        op->orm_no_opattrs = 0;
        op->orm_modlist = mx->mx_orig;
        for ( ml = mx->mx_free; ml; ml = mx->mx_free ) {
                mx->mx_free = ml->sml_next;
                op->o_tmpfree( ml, op->o_tmpmemctx );
        }
+       op->o_callback = sc->sc_next;
+       op->o_tmpfree( sc, op->o_tmpmemctx );
        return SLAP_CB_CONTINUE;
 }
 
@@ -2016,14 +2032,6 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
                        &mod->sml_nvalues[0], &a->a_nvals[0], &text );
                overlay_entry_release_ov( op, e, 0, on );
        }
-       /* mod is newer, let it go */
-       if ( match > 0 ) {
-               for ( mod = op->orm_modlist; mod; mod=mod->sml_next ) {
-                       if ( mod->sml_op == LDAP_MOD_DELETE )
-                               mod->sml_op = SLAP_MOD_SOFTDEL;
-               }
-               return SLAP_CB_CONTINUE;
-       }
        /* equal? Should never happen */
        if ( match == 0 )
                return LDAP_SUCCESS;
@@ -2049,20 +2057,32 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
         *
         * 4. Swap original modlist back in response callback so
         *    that accesslog logs the original mod.
+        *
+        * Even if the mod is newer, other out-of-order changes may
+        * have been committed, forcing us to tweak the modlist:
+        * 1. Save/copy original modlist.
+        * 2. Change deletes to soft deletes.
+        * 3. Change Adds of single-valued attrs to Replace.
         */
 
-       newlist = mods_dup( op, op->orm_modlist );
+       newlist = mods_dup( op, op->orm_modlist, match );
 
-       {
+       /* mod is older */
+       if ( match < 0 ) {
                Operation op2 = *op;
                AttributeName an[2];
                const char *text;
-               slap_callback cb;
                struct berval bv;
                char *ptr;
+               Modifications *ml;
                int size, rc;
                SlapReply rs1 = {0};
-               resolve_ctxt rx = { si, newlist };
+               resolve_ctxt rx;
+               slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, NULL };
+
+               rx.rx_si = si;
+               rx.rx_mods = newlist;
+               cb.sc_private = &rx;
 
                op2.o_tag = LDAP_REQ_SEARCH;
                op2.ors_scope = LDAP_SCOPE_SUBTREE;
@@ -2089,8 +2109,6 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
                op2.ors_filter = str2filter_x( op, op2.ors_filterstr.bv_val );
 
                op2.o_callback = &cb;
-               cb.sc_response = syncrepl_resolve_cb;
-               cb.sc_private = &rx;
                op2.o_bd = select_backend( &op2.o_req_ndn, 1 );
                op2.o_bd->be_search( &op2, &rs1 );
                newlist = rx.rx_mods;
@@ -2105,6 +2123,7 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
                sc->sc_response = syncrepl_modify_cb;
                sc->sc_private = mx;
                sc->sc_next = op->o_callback;
+               sc->sc_cleanup = NULL;
                op->o_callback = sc;
                op->orm_no_opattrs = 1;
                mx->mx_orig = op->orm_modlist;
@@ -2114,6 +2133,11 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
                                ml->sml_flags = 0;
                                ml->sml_op = SLAP_MOD_SOFTDEL;
                        }
+                       else if ( ml->sml_op == LDAP_MOD_DELETE )
+                               ml->sml_op = SLAP_MOD_SOFTDEL;
+                       else if ( ml->sml_op == LDAP_MOD_ADD &&
+                               ml->sml_desc->ad_type->sat_atype.at_single_value )
+                               ml->sml_op = LDAP_MOD_REPLACE;
                }
                op->orm_modlist = newlist;
                op->o_csn = mod->sml_nvalues[0];
@@ -2292,6 +2316,7 @@ syncrepl_message_to_op(
                        rc = op->o_bd->be_modify( op, &rs );
                        if ( SLAP_MULTIMASTER( op->o_bd )) {
                                LDAP_SLIST_REMOVE( &op->o_extra, &oes.oe, OpExtra, oe_next );
+                               BER_BVZERO( &op->o_csn );
                        }
                        modlist = op->orm_modlist;
                        Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
@@ -2611,7 +2636,7 @@ typedef struct dninfo {
        int delOldRDN;  /* Was old RDN deleted? */
        Modifications **modlist;        /* the modlist we received */
        Modifications *mods;    /* the modlist we compared */
-       Attribute *oldNattr;    /* old naming attr */
+       int oldNcount;          /* #values of old naming attr */
        AttributeDescription *oldDesc;  /* for renames */
        AttributeDescription *newDesc;  /* for renames */
 } dninfo;
@@ -2792,11 +2817,26 @@ syncrepl_entry(
                                /* FIXME: op->o_csn is assumed to be
                                 * on the thread's slab; this needs
                                 * to be cleared ASAP.
-                                * What happens if already present?
                                 */
-                               assert( BER_BVISNULL( &op->o_csn ) );
                                op->o_csn = a->a_vals[0];
                                freecsn = 0;
+                               /* There was no cookie CSN attached to this op,
+                                * make sure it's new enough
+                                */
+                               if ( !syncCSN ) {
+                                       int i, sid = slap_parse_csn_sid( &a->a_vals[0] );
+                                       for ( i = 0; i<si->si_cookieState->cs_num; i++ ) {
+                                               if ( sid < si->si_cookieState->cs_sids[i] )
+                                                       break;
+                                               if ( sid == si->si_cookieState->cs_sids[i] ) {
+                                                       if ( ber_bvcmp( &a->a_vals[0], &si->si_cookieState->cs_vals[i] ) <= 0 ) {
+                                                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s entryCSN too old, ignoring %s (%s)\n",
+                                                               si->si_ridtxt, a->a_vals[0].bv_val, entry->e_name.bv_val );
+                                                               goto done;
+                                                       }
+                                               }
+                                       }
+                               }
                        }
                }
 retry_add:;
@@ -2823,8 +2863,24 @@ retry_add:;
 
                        case LDAP_REFERRAL:
                        /* we assume that LDAP_NO_SUCH_OBJECT is returned 
-                        * only if the suffix entry is not present */
+                        * only if the suffix entry is not present.
+                        * This should not happen during Persist phase.
+                        */
                        case LDAP_NO_SUCH_OBJECT:
+                               if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
+                                       si->si_refreshDone ) {
+                                       /* Something's wrong, start over */
+                                       ber_bvarray_free( si->si_syncCookie.ctxcsn );
+                                       si->si_syncCookie.ctxcsn = NULL;
+                                       ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+                                       ber_bvarray_free( si->si_cookieState->cs_vals );
+                                       ch_free( si->si_cookieState->cs_sids );
+                                       si->si_cookieState->cs_vals = NULL;
+                                       si->si_cookieState->cs_sids = 0;
+                                       si->si_cookieState->cs_num = 0;
+                                       ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+                                       return LDAP_NO_SUCH_OBJECT;
+                               }
                                rc = syncrepl_add_glue( op, entry );
                                entry = NULL;
                                break;
@@ -2915,10 +2971,10 @@ retry_add:;
                         * If delOldRDN is TRUE then we should see a delete modop
                         * for oldDesc. We might see a replace instead.
                         *  delete with no values: therefore newDesc != oldDesc.
-                        *   if oldNattr had only one value, then Drop this op.
+                        *   if oldNcount == 1, then Drop this op.
                         *  delete with 1 value: can only be the oldRDN value. Drop op.
                         *  delete with N values: Drop oldRDN value, keep remainder.
-                        *  replace with 1 value: if oldNattr had only one value and
+                        *  replace with 1 value: if oldNcount == 1 and
                         *     newDesc == oldDesc, Drop this op.
                         * Any other cases must be left intact.
                         *
@@ -2939,7 +2995,7 @@ retry_add:;
                                                        continue;
                                                }
                                                if ( mod->sml_numvals <= 1 &&
-                                                       dni.oldNattr->a_numvals == 1 &&
+                                                       dni.oldNcount == 1 &&
                                                        ( mod->sml_op == LDAP_MOD_DELETE ||
                                                          mod->sml_op == LDAP_MOD_REPLACE )) {
                                                        if ( mod->sml_op == LDAP_MOD_REPLACE )
@@ -3072,7 +3128,7 @@ retry_modrdn:;
 
                        /* NOTE: noSuchObject should result because the new superior
                         * has not been added yet (ITS#6472) */
-                       if ( rc == LDAP_NO_SUCH_OBJECT && !BER_BVISNULL( op->orr_nnewSup )) {
+                       if ( rc == LDAP_NO_SUCH_OBJECT && op->orr_nnewSup != NULL ) {
                                Operation op2 = *op;
                                rc = syncrepl_add_glue_ancestors( &op2, entry );
                                if ( rc == LDAP_SUCCESS ) {
@@ -3135,10 +3191,15 @@ retry_modrdn:;
                        op->o_req_ndn = dni.ndn;
                        op->o_tag = LDAP_REQ_DELETE;
                        op->o_bd = si->si_wbe;
+                       if ( !syncCSN ) {
+                               slap_queue_csn( op, si->si_syncCookie.ctxcsn );
+                       }
                        rc = op->o_bd->be_delete( op, &rs_delete );
                        Debug( LDAP_DEBUG_SYNC,
                                        "syncrepl_entry: %s be_delete %s (%d)\n", 
                                        si->si_ridtxt, op->o_req_dn.bv_val, rc );
+                       if ( rc == LDAP_NO_SUCH_OBJECT )
+                               rc = LDAP_SUCCESS;
 
                        while ( rs_delete.sr_err == LDAP_SUCCESS
                                && op->o_delete_glue_parent ) {
@@ -3473,8 +3534,8 @@ syncrepl_add_glue_ancestors(
        }
        
        if ( !BER_BVISEMPTY( &ptr ) ) {
-               dn.bv_len -= ptr.bv_len + 1;
-               dn.bv_val += ptr.bv_len + 1;
+               dn.bv_len -= ptr.bv_len + ( suffrdns != 0 );
+               dn.bv_val += ptr.bv_len + ( suffrdns != 0 );
        }
 
        /* the normalizedDNs are always the same length, no counting
@@ -4091,7 +4152,10 @@ dn_callback(
                                        dni->oldDesc = ad;
                                        for ( oldpos=0, a=rs->sr_entry->e_attrs;
                                                a && a->a_desc != ad; oldpos++, a=a->a_next );
-                                       dni->oldNattr = a;
+                                       /* a should not be NULL but apparently it happens.
+                                        * ITS#7144
+                                        */
+                                       dni->oldNcount = a ? a->a_numvals : 0;
                                        for ( newpos=0, a=dni->new_entry->e_attrs;
                                                a && a->a_desc != ad; newpos++, a=a->a_next );
                                        if ( !a || oldpos != newpos || attr_valfind( a,
@@ -5470,13 +5534,13 @@ syncrepl_config( ConfigArgs *c )
                                                                ldap_pvt_runqueue_stoptask( &slapd_rq, re );
                                                                isrunning = 1;
                                                        }
-                                                       ldap_pvt_runqueue_remove( &slapd_rq, re );
-                                                       ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
-
                                                        if ( ldap_pvt_thread_pool_retract( &connection_pool,
                                                                        re->routine, re ) > 0 )
                                                                isrunning = 0;
 
+                                                       ldap_pvt_runqueue_remove( &slapd_rq, re );
+                                                       ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
                                                        ldap_pvt_thread_mutex_unlock( &si->si_mutex );
                                                }
                                        }