]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/syncrepl.c
Merge remote branch 'origin/mdb.master' into OPENLDAP_REL_ENG_2_4
[openldap] / servers / slapd / syncrepl.c
index 204f064e97b4540a896794f7c6ed1ee74ddfd07b..7c07b90873d859fdf57189edc8bb92c9c9dd4448 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.
@@ -131,7 +131,7 @@ static int syncrepl_message_to_op(
                                        syncinfo_t *, Operation *, LDAPMessage * );
 static int syncrepl_message_to_entry(
                                        syncinfo_t *, Operation *, LDAPMessage *,
-                                       Modifications **, Entry **, int );
+                                       Modifications **, Entry **, int, struct berval* );
 static int syncrepl_entry(
                                        syncinfo_t *, Operation*, Entry*,
                                        Modifications**,int, struct berval*,
@@ -667,7 +667,7 @@ do_syncrep1(
                        LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );
 
                        /* ctxcsn wasn't parsed yet, do it now */
-                       slap_parse_sync_cookie( sc, op->o_tmpmemctx );
+                       slap_parse_sync_cookie( sc, NULL );
                        slap_sync_cookie_free( &si->si_syncCookie, 0 );
                        slap_dup_sync_cookie( &si->si_syncCookie, sc );
                        slap_sync_cookie_free( sc, 1 );
@@ -833,7 +833,7 @@ do_syncrep2(
                tout_p, &msg ) ) > 0 )
        {
                int                             match, punlock, syncstate;
-               struct berval   *retdata, syncUUID, cookie = BER_BVNULL;
+               struct berval   *retdata, syncUUID[2], cookie = BER_BVNULL;
                char                    *retoid;
                LDAPControl             **rctrls = NULL, *rctrlp = NULL;
                BerVarray               syncUUIDs;
@@ -885,7 +885,7 @@ do_syncrep2(
                                goto done;
                        }
                        ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
-                       if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID )
+                       if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID[0] )
                                        == LBER_ERROR ) {
                                bdn.bv_val[bdn.bv_len] = '\0';
                                Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s malformed message (%s)\n",
@@ -896,7 +896,7 @@ do_syncrep2(
                        }
                        /* FIXME: what if syncUUID is NULL or empty?
                         * (happens with back-sql...) */
-                       if ( BER_BVISEMPTY( &syncUUID ) ) {
+                       if ( BER_BVISEMPTY( &syncUUID[0] ) ) {
                                bdn.bv_val[bdn.bv_len] = '\0';
                                Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
                                        "got empty syncUUID with LDAP_SYNC_%s (%s)\n",
@@ -992,6 +992,7 @@ do_syncrep2(
                                        case LDAP_NO_SUCH_OBJECT:
                                        case LDAP_NO_SUCH_ATTRIBUTE:
                                        case LDAP_TYPE_OR_VALUE_EXISTS:
+                                       case LDAP_NOT_ALLOWED_ON_NONLEAF:
                                                rc = LDAP_SYNC_REFRESH_REQUIRED;
                                                si->si_logstate = SYNCLOG_FALLBACK;
                                                ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
@@ -1007,10 +1008,10 @@ do_syncrep2(
                                                break;
                                }
                        } else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
-                               &modlist, &entry, syncstate ) ) == LDAP_SUCCESS )
+                               &modlist, &entry, syncstate, syncUUID ) ) == LDAP_SUCCESS )
                        {
                                if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
-                                       syncstate, &syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
+                                       syncstate, syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
                                        syncCookie.ctxcsn )
                                {
                                        rc = syncrepl_updateCookie( si, op, &syncCookie );
@@ -1961,6 +1962,7 @@ drop:
                                }
                        }
                        slap_mods_free( newmods, 1 );
+                       rx->rx_mods = oldmods;
                }
        }
        return LDAP_SUCCESS;
@@ -2077,8 +2079,12 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
                Modifications *ml;
                int size, rc;
                SlapReply rs1 = {0};
-               resolve_ctxt rx = { si, newlist };
-               slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, &rx };
+               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;
@@ -2411,7 +2417,8 @@ syncrepl_message_to_entry(
        LDAPMessage     *msg,
        Modifications   **modlist,
        Entry                   **entry,
-       int             syncstate
+       int             syncstate,
+       struct berval   *syncUUID
 )
 {
        Entry           *e = NULL;
@@ -2453,6 +2460,14 @@ syncrepl_message_to_entry(
                return LDAP_OTHER;
        }
 
+       /* syncUUID[0] is normalized UUID received over the wire
+        * syncUUID[1] is denormalized UUID, generated here
+        */
+       (void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], op->o_tmpmemctx );
+       Debug( LDAP_DEBUG_SYNC,
+               "syncrepl_message_to_entry: %s DN: %s, UUID: %s\n",
+               si->si_ridtxt, bdn.bv_val, syncUUID[1].bv_val );
+
        if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
                /* NOTE: this could be done even before decoding the DN,
                 * although encoding errors wouldn't be detected */
@@ -2632,7 +2647,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;
@@ -2673,7 +2688,6 @@ syncrepl_entry(
        Backend *be = op->o_bd;
        slap_callback   cb = { NULL, NULL, NULL, NULL };
        int syncuuid_inserted = 0;
-       struct berval   syncUUID_strrep = BER_BVNULL;
 
        SlapReply       rs_search = {REP_RESULT};
        Filter f = {0};
@@ -2703,14 +2717,13 @@ syncrepl_entry(
                }
        }
 
-       (void)slap_uuidstr_from_normalized( &syncUUID_strrep, syncUUID, op->o_tmpmemctx );
        if ( syncstate != LDAP_SYNC_DELETE ) {
                Attribute       *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryUUID );
 
                if ( a == NULL ) {
                        /* add if missing */
                        attr_merge_one( entry, slap_schema.si_ad_entryUUID,
-                               &syncUUID_strrep, syncUUID );
+                               &syncUUID[1], syncUUID );
 
                } else if ( !bvmatch( &a->a_nvals[0], syncUUID ) ) {
                        /* replace only if necessary */
@@ -2719,7 +2732,7 @@ syncrepl_entry(
                                ber_dupbv( &a->a_nvals[0], syncUUID );
                        }
                        ber_memfree( a->a_vals[0].bv_val );
-                       ber_dupbv( &a->a_vals[0], &syncUUID_strrep );
+                       ber_dupbv( &a->a_vals[0], &syncUUID[1] );
                }
        }
 
@@ -2730,16 +2743,16 @@ syncrepl_entry(
 
        if ( syncuuid_inserted ) {
                Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s inserted UUID %s\n",
-                       si->si_ridtxt, syncUUID_strrep.bv_val, 0 );
+                       si->si_ridtxt, syncUUID[1].bv_val, 0 );
        }
        op->ors_filter = &f;
 
-       op->ors_filterstr.bv_len = STRLENOF( "(entryUUID=)" ) + syncUUID_strrep.bv_len;
+       op->ors_filterstr.bv_len = STRLENOF( "(entryUUID=)" ) + syncUUID[1].bv_len;
        op->ors_filterstr.bv_val = (char *) slap_sl_malloc(
                op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); 
        AC_MEMCPY( op->ors_filterstr.bv_val, "(entryUUID=", STRLENOF( "(entryUUID=" ) );
        AC_MEMCPY( &op->ors_filterstr.bv_val[STRLENOF( "(entryUUID=" )],
-               syncUUID_strrep.bv_val, syncUUID_strrep.bv_len );
+               syncUUID[1].bv_val, syncUUID[1].bv_len );
        op->ors_filterstr.bv_val[op->ors_filterstr.bv_len - 1] = ')';
        op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
 
@@ -2813,9 +2826,7 @@ 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;
                        }
@@ -2844,8 +2855,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;
@@ -2936,10 +2963,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.
                         *
@@ -2960,7 +2987,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 )
@@ -3156,10 +3183,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 ) {
@@ -3189,10 +3221,8 @@ retry_modrdn:;
        }
 
 done:
-       if ( !BER_BVISNULL( &syncUUID_strrep ) ) {
-               slap_sl_free( syncUUID_strrep.bv_val, op->o_tmpmemctx );
-               BER_BVZERO( &syncUUID_strrep );
-       }
+       slap_sl_free( syncUUID[1].bv_val, op->o_tmpmemctx );
+       BER_BVZERO( &syncUUID[1] );
        if ( !BER_BVISNULL( &dni.ndn ) ) {
                op->o_tmpfree( dni.ndn.bv_val, op->o_tmpmemctx );
        }
@@ -3494,8 +3524,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
@@ -4112,7 +4142,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,
@@ -5491,13 +5524,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 );
                                                }
                                        }