]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/syncrepl.c
ITS#8040 experimental Lazy Commit
[openldap] / servers / slapd / syncrepl.c
index 6ad8dc5943308a18ac3016e1b40c3a897c2b0c04..23b638d24f0193048d8866305165aa4936d2577e 100644 (file)
@@ -36,6 +36,8 @@
 #define SUFFIXM_CTX    "<suffix massage>"
 #endif
 
+#define        UUIDLEN 16
+
 struct nonpresent_entry {
        struct berval *npe_name;
        struct berval *npe_nname;
@@ -110,6 +112,7 @@ typedef struct syncinfo_s {
        int                     si_refreshDone;
        int                     si_syncdata;
        int                     si_logstate;
+       int                     si_lazyCommit;
        int                     si_got;
        int                     si_strict_refresh;      /* stop listening during fallback refresh */
        int                     si_too_old;
@@ -126,7 +129,10 @@ typedef struct syncinfo_s {
 } syncinfo_t;
 
 static int syncuuid_cmp( const void *, const void * );
-static int avl_presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
+static int presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
+static void presentlist_delete( Avlnode **av, struct berval *syncUUID );
+static char *presentlist_find( Avlnode *av, struct berval *syncUUID );
+static int presentlist_free( Avlnode *av );
 static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
 static int syncrepl_message_to_op(
                                        syncinfo_t *, Operation *, LDAPMessage * );
@@ -713,6 +719,7 @@ do_syncrep1(
                        ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
                }
 
+               ch_free( si->si_syncCookie.octet_str.bv_val );
                slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
                        si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
                        si->si_syncCookie.sid );
@@ -898,10 +905,10 @@ do_syncrep2(
                        }
                        /* FIXME: what if syncUUID is NULL or empty?
                         * (happens with back-sql...) */
-                       if ( BER_BVISEMPTY( &syncUUID[0] ) ) {
+                       if ( syncUUID[0].bv_len != UUIDLEN ) {
                                bdn.bv_val[bdn.bv_len] = '\0';
                                Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
-                                       "got empty syncUUID with LDAP_SYNC_%s (%s)\n",
+                                       "got empty or invalid syncUUID with LDAP_SYNC_%s (%s)\n",
                                        si->si_ridtxt,
                                        syncrepl_state2str( syncstate ), bdn.bv_val );
                                ldap_controls_free( rctrls );
@@ -910,7 +917,7 @@ do_syncrep2(
                        }
                        punlock = -1;
                        if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
-                               ber_scanf( ber, /*"{"*/ "m}", &cookie );
+                               if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) != LBER_ERROR ) {
 
                                Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
                                        si->si_ridtxt,
@@ -995,6 +1002,7 @@ do_syncrep2(
                                        }
                                        op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
                                }
+                               }
                        }
                        rc = 0;
                        if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
@@ -1169,8 +1177,8 @@ do_syncrep2(
                                {
                                        syncrepl_del_nonpresent( op, si, NULL,
                                                &syncCookie, m );
-                               } else {
-                                       avl_free( si->si_presentlist, ch_free );
+                               } else if ( si->si_presentlist ) {
+                                       presentlist_free( si->si_presentlist );
                                        si->si_presentlist = NULL;
                                }
                        }
@@ -1297,20 +1305,23 @@ do_syncrep2(
                                                ber_scanf( ber, "b", &refreshDeletes );
                                        }
                                        syncUUIDs = NULL;
-                                       ber_scanf( ber, "[W]", &syncUUIDs );
+                                       rc = ber_scanf( ber, "[W]", &syncUUIDs );
                                        ber_scanf( ber, /*"{"*/ "}" );
-                                       if ( refreshDeletes ) {
-                                               syncrepl_del_nonpresent( op, si, syncUUIDs,
-                                                       &syncCookie, m );
-                                               ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
-                                       } else {
-                                               int i;
-                                               for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
-                                                       (void)avl_presentlist_insert( si, &syncUUIDs[i] );
-                                                       slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
+                                       if ( rc != LBER_ERROR ) {
+                                               if ( refreshDeletes ) {
+                                                       syncrepl_del_nonpresent( op, si, syncUUIDs,
+                                                               &syncCookie, m );
+                                                       ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
+                                               } else {
+                                                       int i;
+                                                       for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
+                                                               (void)presentlist_insert( si, &syncUUIDs[i] );
+                                                               slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
+                                                       }
+                                                       slap_sl_free( syncUUIDs, op->o_tmpmemctx );
                                                }
-                                               slap_sl_free( syncUUIDs, op->o_tmpmemctx );
                                        }
+                                       rc = 0;
                                        slap_sync_cookie_free( &syncCookie, 0 );
                                        break;
                                default:
@@ -1347,6 +1358,10 @@ do_syncrep2(
                                        {
                                                rc = syncrepl_updateCookie( si, op, &syncCookie);
                                        }
+                                       if ( si->si_presentlist ) {
+                                               presentlist_free( si->si_presentlist );
+                                               si->si_presentlist = NULL;
+                                       }
                                } 
 
                                ldap_memfree( retoid );
@@ -1523,7 +1538,7 @@ do_syncrepl(
                si->si_refreshPresent = 0;
 
                if ( si->si_presentlist ) {
-                   avl_free( si->si_presentlist, ch_free );
+                   presentlist_free( si->si_presentlist );
                    si->si_presentlist = NULL;
                }
 
@@ -2682,29 +2697,103 @@ typedef struct dninfo {
        AttributeDescription *newDesc;  /* for renames */
 } dninfo;
 
+#define HASHUUID       1
+
 /* return 1 if inserted, 0 otherwise */
 static int
-avl_presentlist_insert(
+presentlist_insert(
        syncinfo_t* si,
        struct berval *syncUUID )
 {
-       struct berval *syncuuid_bv = ch_malloc( sizeof( struct berval ) + syncUUID->bv_len + 1 );
+       char *val;
+
+#ifdef HASHUUID
+       Avlnode **av;
+       unsigned short s;
+
+       if ( !si->si_presentlist )
+               si->si_presentlist = ch_calloc(65536, sizeof( Avlnode * ));
+
+       av = (Avlnode **)si->si_presentlist;
 
-       syncuuid_bv->bv_len = syncUUID->bv_len;
-       syncuuid_bv->bv_val = (char *)&syncuuid_bv[1];
-       AC_MEMCPY( syncuuid_bv->bv_val, syncUUID->bv_val, syncUUID->bv_len );
-       syncuuid_bv->bv_val[ syncuuid_bv->bv_len ] = '\0';
+       val = ch_malloc(UUIDLEN-2);
+       memcpy(&s, syncUUID->bv_val, 2);
+       memcpy(val, syncUUID->bv_val+2, UUIDLEN-2);
 
-       if ( avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
+       if ( avl_insert( &av[s], val,
                syncuuid_cmp, avl_dup_error ) )
        {
-               ch_free( syncuuid_bv );
+               ch_free( val );
                return 0;
        }
+#else
+       val = ch_malloc(UUIDLEN);
+
+       AC_MEMCPY( val, syncUUID->bv_val, UUIDLEN );
+
+       if ( avl_insert( &si->si_presentlist, val,
+               syncuuid_cmp, avl_dup_error ) )
+       {
+               ch_free( val );
+               return 0;
+       }
+#endif
 
        return 1;
 }
 
+static char *
+presentlist_find(
+       Avlnode *av,
+       struct berval *val )
+{
+#ifdef HASHUUID
+       Avlnode **a2 = (Avlnode **)av;
+       unsigned short s;
+
+       memcpy(&s, val->bv_val, 2);
+       return avl_find( a2[s], val->bv_val+2, syncuuid_cmp );
+#else
+       return avl_find( av, val->bv_val, syncuuid_cmp );
+#endif
+}
+
+static int
+presentlist_free( Avlnode *av )
+{
+#ifdef HASHUUID
+       Avlnode **a2 = (Avlnode **)av;
+       int i, count = 0;
+
+       if ( av ) {
+               for (i=0; i<65536; i++) {
+                       if (a2[i])
+                               count += avl_free( a2[i], ch_free );
+               }
+               ch_free( av );
+       }
+       return count;
+#else
+       return avl_free( av, ch_free );
+#endif
+}
+
+static void
+presentlist_delete(
+       Avlnode **av,
+       struct berval *val )
+{
+#ifdef HASHUUID
+       Avlnode **a2 = *(Avlnode ***)av;
+       unsigned short s;
+
+       memcpy(&s, val->bv_val, 2);
+       avl_delete( &a2[s], val->bv_val+2, syncuuid_cmp );
+#else
+       avl_delete( av, val->bv_val, syncuuid_cmp );
+#endif
+}
+
 static int
 syncrepl_entry(
        syncinfo_t* si,
@@ -2735,7 +2824,7 @@ syncrepl_entry(
 
        if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ) ) {
                if ( !si->si_refreshPresent && !si->si_refreshDone ) {
-                       syncuuid_inserted = avl_presentlist_insert( si, syncUUID );
+                       syncuuid_inserted = presentlist_insert( si, syncUUID );
                }
        }
 
@@ -2844,6 +2933,9 @@ syncrepl_entry(
                slap_queue_csn( op, syncCSN );
        }
 
+       if ( !si->si_refreshDone && si->si_lazyCommit )
+               op->o_lazyCommit = SLAP_CONTROL_NONCRITICAL;
+
        slap_op_time( &op->o_time, &op->o_tincr );
        switch ( syncstate ) {
        case LDAP_SYNC_ADD:
@@ -2894,6 +2986,7 @@ retry_add:;
                                        /* Something's wrong, start over */
                                        ber_bvarray_free( si->si_syncCookie.ctxcsn );
                                        si->si_syncCookie.ctxcsn = NULL;
+                                       entry_free( entry );
                                        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 );
@@ -4224,11 +4317,11 @@ nonpresent_callback(
        syncinfo_t *si = op->o_callback->sc_private;
        Attribute *a;
        int count = 0;
-       struct berval* present_uuid = NULL;
+       char *present_uuid = NULL;
        struct nonpresent_entry *np_entry;
 
        if ( rs->sr_type == REP_RESULT ) {
-               count = avl_free( si->si_presentlist, ch_free );
+               count = presentlist_free( si->si_presentlist );
                si->si_presentlist = NULL;
 
        } else if ( rs->sr_type == REP_SEARCH ) {
@@ -4236,8 +4329,7 @@ nonpresent_callback(
                        a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
 
                        if ( a ) {
-                               present_uuid = avl_find( si->si_presentlist, &a->a_nvals[0],
-                                       syncuuid_cmp );
+                               present_uuid = presentlist_find( si->si_presentlist, &a->a_nvals[0] );
                        }
 
                        if ( LogTest( LDAP_DEBUG_SYNC ) ) {
@@ -4261,8 +4353,7 @@ nonpresent_callback(
                        LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
 
                } else {
-                       avl_delete( &si->si_presentlist,
-                               &a->a_nvals[0], syncuuid_cmp );
+                       presentlist_delete( &si->si_presentlist, &a->a_nvals[0] );
                        ch_free( present_uuid );
                }
        }
@@ -4393,11 +4484,11 @@ done:;
 static int
 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
 {
-       const struct berval *uuid1 = v_uuid1;
-       const struct berval *uuid2 = v_uuid2;
-       int rc = uuid1->bv_len - uuid2->bv_len;
-       if ( rc ) return rc;
-       return ( memcmp( uuid1->bv_val, uuid2->bv_val, uuid1->bv_len ) );
+#ifdef HASHUUID
+       return ( memcmp( v_uuid1, v_uuid2, UUIDLEN-2 ));
+#else
+       return ( memcmp( v_uuid1, v_uuid2, UUIDLEN ));
+#endif
 }
 
 void
@@ -4495,7 +4586,7 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                }
                slap_sync_cookie_free( &sie->si_syncCookie, 0 );
                if ( sie->si_presentlist ) {
-                   avl_free( sie->si_presentlist, ch_free );
+                   presentlist_free( sie->si_presentlist );
                }
                while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist ) ) {
                        struct nonpresent_entry* npe;
@@ -4600,6 +4691,7 @@ config_suffixm( ConfigArgs *c, syncinfo_t *si )
 /* FIXME: undocumented */
 #define EXATTRSSTR             "exattrs"
 #define MANAGEDSAITSTR         "manageDSAit"
+#define LAZY_COMMIT            "lazycommit"
 
 /* mandatory */
 enum {
@@ -5098,6 +5190,10 @@ parse_syncrepl_line(
                                        STRLENOF( STRICT_REFRESH ) ) )
                {
                        si->si_strict_refresh = 1;
+               } else if ( !strncasecmp( c->argv[ i ], LAZY_COMMIT,
+                                       STRLENOF( LAZY_COMMIT ) ) )
+               {
+                       si->si_lazyCommit = 1;
                } else if ( !bindconf_parse( c->argv[i], &si->si_bindconf ) ) {
                        si->si_got |= GOT_BINDCONF;
                } else {
@@ -5498,6 +5594,11 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
                        ptr = lutil_strcopy( ptr, bc.bv_val );
                }
        }
+
+       if ( si->si_lazyCommit ) {
+               ptr = lutil_strcopy( ptr, " " LAZY_COMMIT );
+       }
+
        bc.bv_len = ptr - buf;
        bc.bv_val = buf;
        ber_dupbv( bv, &bc );