]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/syncrepl.c
silence warning
[openldap] / servers / slapd / syncrepl.c
index 90d719e02cbaef72ffa64e62fd716746290516ba..204f064e97b4540a896794f7c6ed1ee74ddfd07b 100644 (file)
@@ -44,17 +44,17 @@ struct nonpresent_entry {
 
 typedef struct cookie_state {
        ldap_pvt_thread_mutex_t cs_mutex;
+       struct berval *cs_vals;
+       int *cs_sids;
        int     cs_num;
        int cs_age;
        int cs_ref;
-       struct berval *cs_vals;
-       int *cs_sids;
-       
+
        /* pending changes, not yet committed */
        ldap_pvt_thread_mutex_t cs_pmutex;
-       int     cs_pnum;
        struct berval *cs_pvals;
        int *cs_psids;
+       int     cs_pnum;
 } cookie_state;
 
 #define        SYNCDATA_DEFAULT        0       /* entries are plain LDAP entries */
@@ -691,6 +691,7 @@ do_syncrep1(
                                        for (i=0; !BER_BVISNULL( &csn[i] ); i++);
                                        si->si_cookieState->cs_num = i;
                                        si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
+                                       slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
                                }
                        }
                        if ( si->si_cookieState->cs_num ) {
@@ -822,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;
@@ -924,6 +925,9 @@ do_syncrep2(
                                                int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
                                                check_syncprov( op, si );
                                                for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
+                                                       /* new SID */
+                                                       if ( sid < si->si_cookieState->cs_sids[i] )
+                                                               break;
                                                        if ( si->si_cookieState->cs_sids[i] == sid ) {
                                                                if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
                                                                        bdn.bv_val[bdn.bv_len] = '\0';
@@ -946,6 +950,8 @@ do_syncrep2(
                                                                ldap_pvt_thread_yield();
                                                }
                                                for ( i =0; i<si->si_cookieState->cs_pnum; i++ ) {
+                                                       if ( sid < si->si_cookieState->cs_psids[i] )
+                                                               break;
                                                        if ( si->si_cookieState->cs_psids[i] == sid ) {
                                                                if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_pvals[i] ) <= 0 ) {
                                                                        bdn.bv_val[bdn.bv_len] = '\0';
@@ -962,11 +968,11 @@ do_syncrep2(
                                                        }
                                                }
                                                /* new SID, add it */
-                                               if ( i == si->si_cookieState->cs_pnum ) {
-                                                       value_add( &si->si_cookieState->cs_pvals, syncCookie.ctxcsn );
-                                                       si->si_cookieState->cs_pnum++;
-                                                       si->si_cookieState->cs_psids = ch_realloc( si->si_cookieState->cs_psids, si->si_cookieState->cs_pnum * sizeof(int));
-                                                       si->si_cookieState->cs_psids[i] = sid;
+                                               if ( i == si->si_cookieState->cs_pnum ||
+                                                       sid != si->si_cookieState->cs_psids[i] ) {
+                                                       slap_insert_csn_sids(
+                                                               (struct sync_cookie *)&si->si_cookieState->cs_pvals,
+                                                               i, sid, syncCookie.ctxcsn );
                                                }
                                                assert( punlock < 0 );
                                                punlock = i;
@@ -1235,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,
@@ -1783,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);
@@ -1827,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;
@@ -1869,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--;
                        }
@@ -1955,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;
 }
 
@@ -2010,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;
@@ -2043,20 +2057,28 @@ 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 };
+               slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, &rx };
 
                op2.o_tag = LDAP_REQ_SEARCH;
                op2.ors_scope = LDAP_SCOPE_SUBTREE;
@@ -2083,8 +2105,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;
@@ -2099,6 +2119,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;
@@ -2108,6 +2129,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];
@@ -2286,6 +2312,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,
@@ -3066,7 +3093,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 ) {
@@ -3602,6 +3629,7 @@ syncrepl_updateCookie(
        Backend *be = op->o_bd;
        Modifications mod;
        struct berval first = BER_BVNULL;
+       struct sync_cookie sc;
 #ifdef CHECK_CSN
        Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax;
 #endif
@@ -3631,44 +3659,45 @@ syncrepl_updateCookie(
 #endif
 
        /* clone the cookieState CSNs so we can Replace the whole thing */
-       mod.sml_numvals = si->si_cookieState->cs_num;
-       mod.sml_values = op->o_tmpalloc(( mod.sml_numvals+1 )*sizeof(struct berval), op->o_tmpmemctx );
-       for ( i=0; i<mod.sml_numvals; i++ )
-               mod.sml_values[i] = si->si_cookieState->cs_vals[i];
-       BER_BVZERO( &mod.sml_values[i] );
+       sc.numcsns = si->si_cookieState->cs_num;
+       if ( sc.numcsns ) {
+               ber_bvarray_dup_x( &sc.ctxcsn, si->si_cookieState->cs_vals, NULL );
+               sc.sids = ch_malloc( sc.numcsns * sizeof(int));
+               for ( i=0; i<sc.numcsns; i++ )
+                       sc.sids[i] = si->si_cookieState->cs_sids[i];
+       } else {
+               sc.ctxcsn = NULL;
+               sc.sids = NULL;
+       }
 
        /* find any CSNs in the syncCookie that are newer than the cookieState */
        for ( i=0; i<syncCookie->numcsns; i++ ) {
-               for ( j=0; j<si->si_cookieState->cs_num; j++ ) {
-                       if ( syncCookie->sids[i] != si->si_cookieState->cs_sids[j] )
+               for ( j=0; j<sc.numcsns; j++ ) {
+                       if ( syncCookie->sids[i] < sc.sids[j] )
+                               break;
+                       if ( syncCookie->sids[i] != sc.sids[j] )
                                continue;
                        len = syncCookie->ctxcsn[i].bv_len;
-                       if ( len > si->si_cookieState->cs_vals[j].bv_len )
-                               len = si->si_cookieState->cs_vals[j].bv_len;
+                       if ( len > sc.ctxcsn[j].bv_len )
+                               len = sc.ctxcsn[j].bv_len;
                        if ( memcmp( syncCookie->ctxcsn[i].bv_val,
-                               si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) {
-                               mod.sml_values[j] = syncCookie->ctxcsn[i];
+                               sc.ctxcsn[j].bv_val, len ) > 0 ) {
+                               ber_bvreplace( &sc.ctxcsn[j], &syncCookie->ctxcsn[i] );
                                changed = 1;
-                               if ( BER_BVISNULL( &first ) ) {
-                                       first = syncCookie->ctxcsn[i];
-
-                               } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
-                               {
+                               if ( BER_BVISNULL( &first ) ||
+                                       memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
                                        first = syncCookie->ctxcsn[i];
                                }
                        }
                        break;
                }
                /* there was no match for this SID, it's a new CSN */
-               if ( j == si->si_cookieState->cs_num ) {
-                       mod.sml_values = op->o_tmprealloc( mod.sml_values,
-                               ( mod.sml_numvals+2 )*sizeof(struct berval), op->o_tmpmemctx );
-                       mod.sml_values[mod.sml_numvals++] = syncCookie->ctxcsn[i];
-                       BER_BVZERO( &mod.sml_values[mod.sml_numvals] );
-                       if ( BER_BVISNULL( &first ) ) {
-                               first = syncCookie->ctxcsn[i];
-                       } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
-                       {
+               if ( j == sc.numcsns ||
+                       syncCookie->sids[i] != sc.sids[j] ) {
+                       slap_insert_csn_sids( &sc, j, syncCookie->sids[i],
+                               &syncCookie->ctxcsn[i] );
+                       if ( BER_BVISNULL( &first ) ||
+                               memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
                                first = syncCookie->ctxcsn[i];
                        }
                        changed = 1;
@@ -3677,7 +3706,8 @@ syncrepl_updateCookie(
        /* Should never happen, ITS#5065 */
        if ( BER_BVISNULL( &first ) || !changed ) {
                ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
-               op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
+               ber_bvarray_free( sc.ctxcsn );
+               ch_free( sc.sids );
                return 0;
        }
        op->o_bd = si->si_wbe;
@@ -3695,6 +3725,9 @@ syncrepl_updateCookie(
        /* update contextCSN */
        op->o_dont_replicate = 1;
 
+       mod.sml_numvals = sc.numcsns;
+       mod.sml_values = sc.ctxcsn;
+
        op->orm_modlist = &mod;
        op->orm_no_opattrs = 1;
        rc = op->o_bd->be_modify( op, &rs_modify );
@@ -3718,20 +3751,11 @@ syncrepl_updateCookie(
 
        if ( rs_modify.sr_err == LDAP_SUCCESS ) {
                slap_sync_cookie_free( &si->si_syncCookie, 0 );
-               /* If we replaced any old values */
-               for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
-                       if ( mod.sml_values[i].bv_val != si->si_cookieState->cs_vals[i].bv_val )
-                                       ber_bvreplace( &si->si_cookieState->cs_vals[i],
-                                               &mod.sml_values[i] );
-               }
-               /* Handle any added values */
-               if ( i < mod.sml_numvals ) {
-                       si->si_cookieState->cs_num = mod.sml_numvals;
-                       value_add( &si->si_cookieState->cs_vals, &mod.sml_values[i] );
-                       free( si->si_cookieState->cs_sids );
-                       si->si_cookieState->cs_sids = slap_parse_csn_sids(
-                               si->si_cookieState->cs_vals, si->si_cookieState->cs_num, NULL );
-               }
+               ber_bvarray_free( si->si_cookieState->cs_vals );
+               ch_free( si->si_cookieState->cs_sids );
+               si->si_cookieState->cs_vals = sc.ctxcsn;
+               si->si_cookieState->cs_sids = sc.sids;
+               si->si_cookieState->cs_num = sc.numcsns;
 
                /* Don't just dup the provider's cookie, recreate it */
                si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
@@ -3746,6 +3770,8 @@ syncrepl_updateCookie(
                Debug( LDAP_DEBUG_ANY,
                        "syncrepl_updateCookie: %s be_modify failed (%d)\n",
                        si->si_ridtxt, rs_modify.sr_err, 0 );
+               ch_free( sc.sids );
+               ber_bvarray_free( sc.ctxcsn );
        }
        ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
 
@@ -3753,7 +3779,6 @@ syncrepl_updateCookie(
        op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
        BER_BVZERO( &op->o_csn );
        if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
-       op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
 
 #ifdef CHECK_CSN
        for ( i=0; i<si->si_cookieState->cs_num; i++ ) {