]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#9282 Build a complete cookie for the search
authorOndřej Kuzník <ondra@mistotebe.net>
Thu, 2 Jul 2020 13:11:01 +0000 (14:11 +0100)
committerQuanah Gibson-Mount <quanah@openldap.org>
Thu, 23 Jul 2020 16:53:46 +0000 (16:53 +0000)
servers/slapd/syncrepl.c

index 960b4a99af14f0c608dd4c8a1932ff1ba614d9b2..2d5dd98866506ac487c9f68b1f0b08a8fde64c2d 100644 (file)
@@ -501,6 +501,103 @@ ldap_sync_search(
        return rc;
 }
 
+static int
+merge_state( syncinfo_t *si )
+{
+       int i, j = 0, k, numcsns = 0, alloc = 0, changed = 0;
+       BerVarray new_ctxcsn = si->si_syncCookie.ctxcsn;
+       int *new_sids = NULL;
+
+       /* Count and set up sids */
+       for ( i=0; i < si->si_cookieState->cs_num; i++ ) {
+               if ( si->si_cookieState->cs_sids[i] == -1 ) {
+                       continue;
+               }
+
+               for ( ; j < si->si_syncCookie.numcsns &&
+                                       si->si_syncCookie.sids[j] == -1;
+                               j++ )
+                       alloc = 1; /* Just skip over them */
+
+               for ( ; j < si->si_syncCookie.numcsns &&
+                                       si->si_syncCookie.sids[j] < si->si_cookieState->cs_sids[i];
+                               j++ ) {
+                       if ( si->si_syncCookie.sids[j] != -1 ) {
+                               new_sids = ch_realloc( new_sids, (numcsns+1)*sizeof(int) );
+                               new_sids[numcsns++] = si->si_syncCookie.sids[j];
+                       }
+               }
+
+               if ( j < si->si_syncCookie.numcsns &&
+                               si->si_syncCookie.sids[j] == si->si_cookieState->cs_sids[i] ) j++;
+
+               new_sids = ch_realloc( new_sids, (numcsns+1)*sizeof(int) );
+               new_sids[numcsns++] = si->si_cookieState->cs_sids[i];
+       }
+
+       for ( ; j < si->si_syncCookie.numcsns; j++ ) {
+               if ( si->si_syncCookie.sids[j] != -1 ) {
+                       new_sids = ch_realloc( new_sids, (numcsns+1)*sizeof(int) );
+                       new_sids[numcsns++] = si->si_syncCookie.sids[j];
+               }
+       }
+
+       if ( alloc || numcsns != si->si_syncCookie.numcsns ) {
+               /* Short circuit allocations if we don't need to start over */
+               alloc = 1;
+               new_ctxcsn = ch_calloc( numcsns + 1, sizeof( BerValue ) );
+       }
+
+       i = j = 0;
+       for ( k=0; k < numcsns; k++ ) {
+               while ( i < si->si_cookieState->cs_num &&
+                               si->si_cookieState->cs_sids[i] < new_sids[k] )
+                       i++;
+
+               while ( j < si->si_syncCookie.numcsns &&
+                               si->si_syncCookie.sids[j] < new_sids[k] )
+                       j++;
+
+               if ( j < si->si_syncCookie.numcsns &&
+                               si->si_cookieState->cs_sids[i] == si->si_syncCookie.sids[j] ) {
+                       assert( si->si_cookieState->cs_sids[i] == new_sids[k] );
+                       if ( !bvmatch( &si->si_syncCookie.ctxcsn[j],
+                                       &si->si_cookieState->cs_vals[i] )) {
+                               ber_bvreplace( &new_ctxcsn[k], &si->si_cookieState->cs_vals[i] );
+                               changed = 1;
+                       } else if ( alloc ) {
+                               ber_dupbv( &new_ctxcsn[k], &si->si_syncCookie.ctxcsn[j] );
+                       }
+                       i++;
+                       j++;
+               } else if ( si->si_cookieState->cs_sids[i] == new_sids[k] ) {
+                       changed = 1;
+                       ber_bvreplace( &new_ctxcsn[k], &si->si_cookieState->cs_vals[i] );
+                       i++;
+               } else {
+                       if ( alloc ) {
+                               ber_dupbv( &new_ctxcsn[k], &si->si_syncCookie.ctxcsn[j] );
+                       }
+                       j++;
+               }
+       }
+       assert( i == si->si_cookieState->cs_num );
+       assert( j == si->si_syncCookie.numcsns );
+
+       si->si_syncCookie.numcsns = numcsns;
+       if ( alloc ) {
+               changed = 1;
+               ch_free( si->si_syncCookie.sids );
+               si->si_syncCookie.sids = new_sids;
+
+               ber_bvarray_free( si->si_syncCookie.ctxcsn );
+               si->si_syncCookie.ctxcsn = new_ctxcsn;
+       } else {
+               ch_free( new_sids );
+       }
+       return changed;
+}
+
 static int
 check_syncprov(
        Operation *op,
@@ -571,29 +668,8 @@ check_syncprov(
                        ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
                                si->si_cookieState->cs_vals, NULL );
                        changed = 1;
-               } else {
-                       for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
-                               /* bogus, just dup everything */
-                               if ( si->si_syncCookie.sids[i] == -1 ) {
-                                       ber_bvarray_free( si->si_syncCookie.ctxcsn );
-                                       ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
-                                               si->si_cookieState->cs_vals, NULL );
-                                       changed = 1;
-                                       break;
-                               }
-                               for (j=0; j<si->si_cookieState->cs_num; j++) {
-                                       if ( si->si_syncCookie.sids[i] !=
-                                               si->si_cookieState->cs_sids[j] )
-                                               continue;
-                                       if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
-                                               &si->si_cookieState->cs_vals[j] ))
-                                               break;
-                                       ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
-                                               &si->si_cookieState->cs_vals[j] );
-                                       changed = 1;
-                                       break;
-                               }
-                       }
+               } else if ( merge_state( si ) ) {
+                       changed = 1;
                }
        }
        if ( changed ) {