]> git.sur5r.net Git - openldap/commitdiff
Getting refresh working
authorHoward Chu <hyc@openldap.org>
Sun, 21 Nov 2004 17:59:21 +0000 (17:59 +0000)
committerHoward Chu <hyc@openldap.org>
Sun, 21 Nov 2004 17:59:21 +0000 (17:59 +0000)
servers/slapd/overlays/syncprov.c

index f5e7b88d88301aa1dc8d86670961c41d23ac15fb..d9e29ecd015f5884f0303537c05efbb15aecdd14 100644 (file)
 
 #include "portable.h"
 
-#define        SLAPD_OVER_SYNCPROV     SLAPD_MOD_STATIC
+#define        SLAPD_OVER_SYNCPROV     SLAPD_MOD_DYNAMIC
 
 #ifdef SLAPD_OVER_SYNCPROV
 
+#include <ac/string.h>
+#include "lutil.h"
 #include "slap.h"
 
 /* Record of a persistent search */
@@ -31,8 +33,11 @@ typedef struct syncops {
        struct berval   s_base;         /* ndn of search base */
        ID              s_eid;          /* entryID of search base */
        Operation       *s_op;          /* search op */
+       int             s_flags;        /* search status */
 } syncops;
 
+#define        PS_IS_REFRESHING        0x01
+
 /* Record of which searches matched at premodify step */
 typedef struct syncmatches {
        struct syncmatches *sm_next;
@@ -40,15 +45,11 @@ typedef struct syncmatches {
 } syncmatches;
 
 typedef struct syncprov_info_t {
-       Entry           *si_e;  /* cached ldapsync context */
        syncops         *si_ops;
-       int             si_chkops;      /* checkpointing */
-       int             si_chktime;
-       int             si_numops;      /* number of ops since last checkpoint */
-       time_t  si_chklast;     /* time of last checkpoint */
-       ldap_pvt_thread_mutex_t si_e_mutex;
-       ldap_pvt_thread_mutex_t si_ops_mutex;
-       ldap_pvt_thread_mutex_t si_chk_mutex;
+       struct berval   si_ctxcsn;      /* ldapsync context */
+       int             si_gotcsn;      /* is our ctxcsn up to date? */
+       ldap_pvt_thread_mutex_t si_csn_mutex;
+       ldap_pvt_thread_mutex_t si_ops_mutex;
 } syncprov_info_t;
 
 typedef struct opcookie {
@@ -58,10 +59,26 @@ typedef struct opcookie {
 } opcookie;
 
 typedef struct findcookie {
-       ID fid;
-       struct berval fdn;
+       struct berval *fdn;
+       syncops *fss;
+       int fbase;
+       int fsuffix;
 } findcookie;
 
+static AttributeName csn_anlist[2];
+static AttributeName uuid_anlist[2];
+
+static int
+dn_avl_cmp( const void *c1, const void *c2 )
+{
+       struct berval *bv1 = (struct berval *)c1;
+       struct berval *bv2 = (struct berval *)c2;
+       int rc = bv1->bv_len - bv2->bv_len;
+
+       if ( rc ) return rc;
+       return ber_bvcmp( bv1, bv2 );
+}
+
 static int
 findbase_cb( Operation *op, SlapReply *rs )
 {
@@ -69,8 +86,11 @@ findbase_cb( Operation *op, SlapReply *rs )
 
        if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) {
                findcookie *fc = sc->sc_private;
-               fc->fid = rs->sr_entry->e_id;
-               ber_dupbv_x( &fc->fdn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
+               if ( rs->sr_entry->e_id == fc->fss->s_eid &&
+                       dn_match( &rs->sr_entry->e_nname, &fc->fss->s_base )) {
+                       fc->fbase = 1;
+                       fc->fsuffix = dnIsSuffix( fc->fdn, &rs->sr_entry->e_nname );
+               }
        }
        return LDAP_SUCCESS;
 }
@@ -81,7 +101,7 @@ syncprov_findbase( Operation *op, syncops *ss, findcookie *fc )
        slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
        syncprov_info_t         *si = on->on_bi.bi_private;
 
-       slap_callback cb;
+       slap_callback cb = {0};
        Operation fop;
        SlapReply frs = { REP_RESULT };
        int rc;
@@ -106,7 +126,7 @@ syncprov_findbase( Operation *op, syncops *ss, findcookie *fc )
 
        rc = fop.o_bd->be_search( &fop, &frs );
 
-       if ( fc->fid == ss->s_eid ) return LDAP_SUCCESS;
+       if ( fc->fbase ) return LDAP_SUCCESS;
 
        /* If entryID has changed, then the base of this search has
         * changed. Invalidate the psearch.
@@ -114,39 +134,244 @@ syncprov_findbase( Operation *op, syncops *ss, findcookie *fc )
        return LDAP_NO_SUCH_OBJECT;
 }
 
+#define        FIND_CSN        1
+#define        FIND_PRESENT    2
+
+typedef struct fcsn_cookie {
+       struct berval maxcsn;
+       int gotmatch;
+} fcsn_cookie;
+
+static int
+findcsn_cb( Operation *op, SlapReply *rs )
+{
+       slap_callback *sc = op->o_callback;
+
+       if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) {
+               if ( sc->sc_private ) {
+                       int i;
+                       fcsn_cookie *fc = sc->sc_private;
+                       Attribute *a = attr_find(rs->sr_entry->e_attrs,
+                               slap_schema.si_ad_entryCSN );
+                       i = ber_bvcmp( &a->a_vals[0], op->o_sync_state.ctxcsn );
+                       if ( i == 0 ) fc->gotmatch = 1;
+                       i = ber_bvcmp( &a->a_vals[0], &fc->maxcsn );
+                       if ( i > 0 ) {
+                               fc->maxcsn.bv_len = a->a_vals[0].bv_len;
+                               strcpy(fc->maxcsn.bv_val, a->a_vals[0].bv_val );
+                       }
+               } else {
+                       sc->sc_private = (void *)1;
+               }
+       }
+       return LDAP_SUCCESS;
+}
+
+typedef struct fpres_cookie {
+       int num;
+       BerVarray uuids;
+} fpres_cookie;
+
+static int
+findpres_cb( Operation *op, SlapReply *rs )
+{
+       slap_callback *sc = op->o_callback;
+       fpres_cookie *pc = sc->sc_private;
+       int ret;
+
+       if ( rs->sr_type == REP_SEARCH ) {
+               ret = slap_sync_build_syncUUID_set( op, &pc->uuids, rs->sr_entry );
+               if ( ret > 0 ) {
+                       pc->num++;
+                       if ( pc->num == SLAP_SYNCUUID_SET_SIZE ) {
+                               ret = slap_send_syncinfo( op, rs, LDAP_TAG_SYNC_ID_SET, NULL,
+                                       0, pc->uuids, 0 );
+                               ber_bvarray_free_x( pc->uuids, op->o_tmpmemctx );
+                               pc->uuids = NULL;
+                               pc->num = 0;
+                       }
+               } else {
+                       ret = LDAP_OTHER;
+               }
+       } else if ( rs->sr_type == REP_RESULT ) {
+               ret = rs->sr_err;
+               if ( pc->num ) {
+                       ret = slap_send_syncinfo( op, rs, LDAP_TAG_SYNC_ID_SET, NULL,
+                               0, pc->uuids, 0 );
+                       ber_bvarray_free_x( pc->uuids, op->o_tmpmemctx );
+                       pc->uuids = NULL;
+                       pc->num = 0;
+               }
+       }
+       return ret;
+}
+
+
+static int
+syncprov_findcsn( Operation *op, int mode )
+{
+       slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
+       syncprov_info_t         *si = on->on_bi.bi_private;
+
+       slap_callback cb = {0};
+       Operation fop;
+       SlapReply frs = { REP_RESULT };
+       char buf[LDAP_LUTIL_CSNSTR_BUFSIZE + STRLENOF("(entryCSN<=)")];
+       char cbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
+       struct berval fbuf;
+       Filter cf;
+       AttributeAssertion eq;
+       int rc;
+       fcsn_cookie fcookie;
+       fpres_cookie pcookie;
+       int locked = 0;
+
+       if ( op->o_sync_state.ctxcsn->bv_len >= LDAP_LUTIL_CSNSTR_BUFSIZE ) {
+               return LDAP_OTHER;
+       }
+
+       fop = *op;
+       fop.o_sync_mode = 0;
+
+       fbuf.bv_val = buf;
+       if ( mode == FIND_CSN ) {
+               if ( !si->si_gotcsn ) {
+                       /* If we don't know the current ctxcsn, find it */
+                       ldap_pvt_thread_mutex_lock( &si->si_csn_mutex );
+                       locked = 1;
+               }
+               if ( !si->si_gotcsn ) {
+                       cf.f_choice = LDAP_FILTER_GE;
+                       fop.ors_attrsonly = 0;
+                       fop.ors_attrs = csn_anlist;
+                       fop.ors_slimit = SLAP_NO_LIMIT;
+                       cb.sc_private = &fcookie;
+                       fcookie.maxcsn.bv_val = cbuf;
+                       fcookie.maxcsn.bv_len = 0;
+                       fcookie.gotmatch = 0;
+                       fbuf.bv_len = sprintf( buf, "(entryCSN>=%s)", op->o_sync_state.ctxcsn->bv_val );
+               } else {
+                       if ( locked ) {
+                               ldap_pvt_thread_mutex_unlock( &si->si_csn_mutex );
+                               locked = 1;
+                       }
+                       cf.f_choice = LDAP_FILTER_EQUALITY;
+                       fop.ors_attrsonly = 1;
+                       fop.ors_attrs = slap_anlist_no_attrs;
+                       fop.ors_slimit = 1;
+                       cb.sc_private = NULL;
+                       fbuf.bv_len = sprintf( buf, "(entryCSN=%s)", op->o_sync_state.ctxcsn->bv_val );
+               }
+               cb.sc_response = findcsn_cb;
+
+       } else if ( mode == FIND_PRESENT ) {
+               cf.f_choice = LDAP_FILTER_LE;
+               fop.ors_attrsonly = 0;
+               fop.ors_attrs = uuid_anlist;
+               fop.ors_slimit = SLAP_NO_LIMIT;
+               cb.sc_private = &fcookie;
+               cb.sc_response = findpres_cb;
+               pcookie.num = 0;
+               pcookie.uuids = NULL;
+               fbuf.bv_len = sprintf( buf, "(entryCSN<=%s)", op->o_sync_state.ctxcsn->bv_val );
+       }
+       cf.f_ava = &eq;
+       cf.f_av_desc = slap_schema.si_ad_entryCSN;
+       cf.f_av_value = *op->o_sync_state.ctxcsn;
+       cf.f_next = NULL;
+
+       fop.o_callback = &cb;
+       fop.ors_slimit = 1;
+       fop.ors_tlimit = SLAP_NO_LIMIT;
+       fop.ors_filter = &cf;
+       fop.ors_filterstr = fbuf;
+
+       fop.o_bd->bd_info = on->on_info->oi_orig;
+       rc = fop.o_bd->be_search( &fop, &frs );
+
+       if ( mode == FIND_CSN ) {
+               if ( !si->si_gotcsn ) {
+                       ber_dupbv( &si->si_ctxcsn, &fcookie.maxcsn );
+                       si->si_gotcsn = 1;
+                       ldap_pvt_thread_mutex_unlock( &si->si_csn_mutex );
+                       if ( fcookie.gotmatch ) return LDAP_SUCCESS;
+                       
+               } else {
+                       if ( cb.sc_private ) return LDAP_SUCCESS;
+               }
+       } else if ( mode == FIND_PRESENT ) {
+               return LDAP_SUCCESS;
+       }
+
+       /* If matching CSN was not found, invalidate the context. */
+       return LDAP_NO_SUCH_OBJECT;
+}
+
 static void
-syncprov_matchops( Operation *op, opcookie *opc )
+syncprov_matchops( Operation *op, opcookie *opc, int saveit )
 {
        slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
        syncprov_info_t         *si = on->on_bi.bi_private;
 
-       findcookie fc = { NOID };
+       findcookie fc;
        syncops *ss;
        Entry *e;
        Attribute *a;
        int rc;
 
-       rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
+       fc.fdn = &op->o_req_ndn;
+       rc = be_entry_get_rw( op, fc.fdn, NULL, NULL, 0, &e );
        if ( rc ) return;
 
-       a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID );
-       if ( a )
-               ber_dupbv_x( &opc->suuid, &a->a_vals[0], op->o_tmpmemctx );
+       if ( saveit ) {
+               a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID );
+               if ( a )
+                       ber_dupbv_x( &opc->suuid, &a->a_vals[0], op->o_tmpmemctx );
+       }
 
        ldap_pvt_thread_mutex_lock( &si->si_ops_mutex );
        for (ss = si->si_ops; ss; ss=ss->s_next)
        {
+               syncmatches *sm;
+               int found = 0;
+
                /* validate base */
+               fc.fss = ss;
+               fc.fbase = 0;
+               fc.fsuffix = 0;
                rc = syncprov_findbase( op, ss, &fc );
                if ( rc != LDAP_SUCCESS ) continue;
 
+               /* If we're sending results now, look for this op in old matches */
+               if ( !saveit ) {
+                       syncmatches *old;
+                       for ( sm=opc->smatches, old=(syncmatches *)&opc->smatches; sm;
+                               old=sm, sm=sm->sm_next ) {
+                               if ( sm->sm_op == ss ) {
+                                       found = 1;
+                                       old->sm_next = sm->sm_next;
+                                       op->o_tmpfree( sm, op->o_tmpmemctx );
+                                       break;
+                               }
+                       }
+               }
+
                /* check if current o_req_dn is in scope and matches filter */
-               if ( dnIsSuffix( &op->o_req_ndn, &fc.fdn ) && test_filter( op, e,
-                        ss->s_op->ors_filter ) == LDAP_COMPARE_TRUE ) {
-                       syncmatches *sm = op->o_tmpalloc( sizeof(syncmatches), op->o_tmpmemctx );
-                       sm->sm_next = opc->smatches;
-                       sm->sm_op = ss;
-                       opc->smatches = sm;
+               if ( fc.fsuffix && test_filter( op, e, ss->s_op->ors_filter ) ==
+                       LDAP_COMPARE_TRUE ) {
+                       if ( saveit ) {
+                               sm = op->o_tmpalloc( sizeof(syncmatches), op->o_tmpmemctx );
+                               sm->sm_next = opc->smatches;
+                               sm->sm_op = ss;
+                               opc->smatches = sm;
+                       } else {
+                               /* if found send UPDATE else send ADD */
+                               if ( found ) {
+                               } else {
+                               }
+                       }
+               } else if ( !saveit && found ) {
+                       /* send DELETE */
                }
        }
        ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex );
@@ -160,48 +385,51 @@ syncprov_op_response( Operation *op, SlapReply *rs )
        opcookie *opc = (opcookie *)(cb+1);
        slap_overinst *on = opc->son;
        syncprov_info_t         *si = on->on_bi.bi_private;
+       syncmatches *sm, *snext;
 
        if ( rs->sr_err == LDAP_SUCCESS )
        {
+               struct berval maxcsn;
+               void *memctx = op->o_tmpmemctx;
+
+               ldap_pvt_thread_mutex_lock( &si->si_csn_mutex );
+               op->o_tmpmemctx = NULL;
+               slap_get_commit_csn( op, &maxcsn );
+               op->o_tmpmemctx = memctx;
+               if ( maxcsn.bv_val ) {
+                       free( si->si_ctxcsn.bv_val );
+                       si->si_ctxcsn = maxcsn;
+                       si->si_gotcsn = 1;
+               }
+               ldap_pvt_thread_mutex_unlock( &si->si_csn_mutex );
+
                switch(op->o_tag) {
                case LDAP_REQ_ADD:
-                       /* for each op in si->si_ops:
-                        *   validate base
-                        *   check for scope and filter
-                        *   send ADD msg if matched
-                        */
-                        break;
-               case LDAP_REQ_DELETE:
-                       /* for each match in opc->smatches:
-                        *   send DELETE msg
-                        */
-                        break;
                case LDAP_REQ_MODIFY:
                case LDAP_REQ_MODRDN:
-                       /* for each op in si->si_ops:
-                        *   validate base
-                        *   check for scope and filter
-                        *   if match
-                        *     if match in opc->smatches, send UPDATE
-                        *     else send ADD
-                        *   else
-                        *     if match in opc->smatches, send DELETE
-                        */
-                        break;
                case LDAP_REQ_EXTENDED:
-                       /* for each op in si->si_ops:
-                        *   validate base
-                        *   check for scope and filter
-                        *   send UPDATE msg if matched
+                       syncprov_matchops( op, opc, 0 );
+                       break;
+               case LDAP_REQ_DELETE:
+                       /* for each match in opc->smatches:
+                        *   send DELETE msg
                         */
-                        break;
+                       for ( sm = opc->smatches; sm; sm=sm->sm_next ) {
+                       }
+                       break;
                }
+
+       }
+       for (sm = opc->smatches; sm; sm=snext) {
+               snext = sm->sm_next;
+               op->o_tmpfree( sm, op->o_tmpmemctx );
        }
        op->o_callback = cb->sc_next;
        op->o_tmpfree(cb, op->o_tmpmemctx);
        return SLAP_CB_CONTINUE;
 }
 
+#if 0
 static int
 syncprov_op_compare( Operation *op, SlapReply *rs )
 {
@@ -261,9 +489,10 @@ return_results:;
 
        return SLAP_CB_CONTINUE;
 }
+#endif
        
 static int
-syncprov_op_add( Operation *op, SlapReply *rs )
+syncprov_op_mod( Operation *op, SlapReply *rs )
 {
        slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
        syncprov_info_t         *si = on->on_bi.bi_private;
@@ -277,182 +506,243 @@ syncprov_op_add( Operation *op, SlapReply *rs )
                cb->sc_private = opc;
                cb->sc_next = op->o_callback;
                op->o_callback = cb;
+
+               if ( op->o_tag != LDAP_REQ_ADD )
+                       syncprov_matchops( op, opc, 1 );
        }
 
        return SLAP_CB_CONTINUE;
 }
 
 static int
-syncprov_op_delete( Operation *op, SlapReply *rs )
+syncprov_op_extended( Operation *op, SlapReply *rs )
 {
-       slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
-       syncprov_info_t         *si = on->on_bi.bi_private;
-
-       if ( si->si_ops )
-       {
-               slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
-               opcookie *opc = (opcookie *)(cb+1);
-               opc->son = on;
-               cb->sc_response = syncprov_op_response;
-               cb->sc_private = opc;
-               cb->sc_next = op->o_callback;
-               op->o_callback = cb;
-
-               syncprov_matchops( op, opc );
-       }
+       if ( exop_is_write( op ))
+               return syncprov_op_mod( op, rs );
 
        return SLAP_CB_CONTINUE;
 }
 
 static int
-syncprov_op_modify( Operation *op, SlapReply *rs )
+syncprov_search_cleanup( Operation *op, SlapReply *rs )
 {
-       slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
-       syncprov_info_t         *si = on->on_bi.bi_private;
-
-       if ( si->si_ops )
-       {
-               slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
-               opcookie *opc = (opcookie *)(cb+1);
-               opc->son = on;
-               cb->sc_response = syncprov_op_response;
-               cb->sc_private = opc;
-               cb->sc_next = op->o_callback;
-               op->o_callback = cb;
-
-               syncprov_matchops( op, opc );
+       if ( rs->sr_ctrls ) {
+               free( rs->sr_ctrls[0] );
+               op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
        }
-
-       return SLAP_CB_CONTINUE;
+       return 0;
 }
 
 static int
-syncprov_op_modrdn( Operation *op, SlapReply *rs )
+syncprov_search_response( Operation *op, SlapReply *rs )
 {
-       slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
+       slap_callback *cb = op->o_callback;
+       slap_overinst *on = cb->sc_private;
        syncprov_info_t         *si = on->on_bi.bi_private;
 
-       if ( si->si_ops )
-       {
-               slap_callback *cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
-               opcookie *opc = (opcookie *)(cb+1);
-               opc->son = on;
-               cb->sc_response = syncprov_op_response;
-               cb->sc_private = opc;
-               cb->sc_next = op->o_callback;
-               op->o_callback = cb;
-
-               syncprov_matchops( op, opc );
+       if ( rs->sr_type == REP_SEARCH ) {
+               int i;
+               if ( op->o_sync_state.ctxcsn ) {
+                       Attribute *a = attr_find( rs->sr_entry->e_attrs,
+                               slap_schema.si_ad_entryCSN );
+                       /* Don't send the ctx entry twice */
+                       if ( bvmatch( &a->a_nvals[0], op->o_sync_state.ctxcsn ))
+                               return LDAP_SUCCESS;
+               }
+               rs->sr_ctrls = op->o_tmpalloc( sizeof(LDAPControl *)*2,
+                       op->o_tmpmemctx );
+               rs->sr_ctrls[1] = NULL;
+               rs->sr_err = slap_build_sync_state_ctrl( op, rs, rs->sr_entry,
+                       LDAP_SYNC_ADD, rs->sr_ctrls, 0, 0, NULL );
+       } else if (rs->sr_type == REP_RESULT ) {
+               struct berval cookie;
+               rs->sr_ctrls = op->o_tmpalloc( sizeof(LDAPControl *)*2,
+                       op->o_tmpmemctx );
+               rs->sr_ctrls[1] = NULL;
+               slap_compose_sync_cookie( op, &cookie,
+                       &op->ors_filter->f_and->f_ava->aa_value,
+                       op->o_sync_state.sid, op->o_sync_state.rid );
+               rs->sr_err = slap_build_sync_done_ctrl( op, rs, rs->sr_ctrls,
+                       0, 1, &cookie, LDAP_SYNC_REFRESH_PRESENTS );
        }
 
        return SLAP_CB_CONTINUE;
 }
 
-static const struct berval * write_exop[] = {
-       &slap_EXOP_MODIFY_PASSWD,
-       NULL
-};
-
 static int
-syncprov_op_extended( Operation *op, SlapReply *rs )
+syncprov_op_search( Operation *op, SlapReply *rs )
 {
        slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
-       syncprov_info_t         *si = on->on_bi.bi_private;
+       syncprov_info_t         *si = (syncprov_info_t *)on->on_bi.bi_private;
+       slap_callback   *cb;
+       int gotstate = 0;
+       Filter *fand, *fava;
 
-       if ( si->si_ops )
-       {
-               int i, doit = 0;
+       if ( !op->o_sync_mode ) return SLAP_CB_CONTINUE;
 
-               for ( i=0; write_exop[i]; i++ )
-               {
-                       if ( !ber_bvcmp( write_exop[i], &op->oq_extended.rs_reqoid ))
-                       {
-                               doit = 1;
-                               break;
-                       }
+       if ( op->ors_deref & LDAP_DEREF_SEARCHING ) {
+               send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "illegal value for derefAliases" );
+               return rs->sr_err;
+       }
+
+       /* If we have a cookie, handle the PRESENT lookups
+        */
+       if ( op->o_sync_state.ctxcsn ) {
+               /* Is the CSN in a valid format? */
+               if ( op->o_sync_state.ctxcsn->bv_len >= LDAP_LUTIL_CSNSTR_BUFSIZE ) {
+                       send_ldap_error( op, rs, LDAP_OTHER, "invalid sync cookie" );
+                       return rs->sr_err;
                }
-               if ( doit )
-               {
-                       slap_callback *cb = op->o_tmpcalloc(1,
-                               sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
-                       opcookie *opc = (opcookie *)(cb+1);
-                       opc->son = on;
-                       cb->sc_response = syncprov_op_response;
-                       cb->sc_private = opc;
-                       cb->sc_next = op->o_callback;
-                       op->o_callback = cb;
-
-                       syncprov_matchops( op, opc );
+               /* Is the CSN still present in the database? */
+               if ( syncprov_findcsn( op, FIND_CSN ) != LDAP_SUCCESS ) {
+                       /* No, so a reload is required */
+                       if ( op->o_sync_rhint == 0 ) {
+                               send_ldap_error( op, rs, LDAP_SYNC_REFRESH_REQUIRED, "sync cookie is stale" );
+                               return rs->sr_err;
+                       }
+               } else {
+                       /* Does it match the current ctxCSN? */
+                       if ( bvmatch( op->o_sync_state.ctxcsn, &si->si_ctxcsn )) {
+                               struct berval cookie;
+                               LDAPControl     *ctrls[2];
+
+                               ctrls[0] = NULL;
+                               ctrls[1] = NULL;
+                               slap_compose_sync_cookie( op, &cookie, op->o_sync_state.ctxcsn,
+                                       op->o_sync_state.sid, op->o_sync_state.rid );
+                               slap_build_sync_done_ctrl( op, rs, ctrls, 0, 1,
+                                       &cookie, LDAP_SYNC_REFRESH_DELETES );
+                               rs->sr_err = LDAP_SUCCESS;
+                               send_ldap_result( op, rs );
+                               free( cookie.bv_val );
+                               return rs->sr_err;
+                       }
+                       gotstate = 1;
+                       /* OK, let's send all the Present UUIDs */
+                       if ( syncprov_findcsn( op, FIND_PRESENT ) != LDAP_SUCCESS ) {
+                               send_ldap_result( op, rs );
+                               return rs->sr_err;
+                       }
                }
        }
 
-       return SLAP_CB_CONTINUE;
-}
+       if ( !gotstate && !si->si_gotcsn ) {
+               struct berval bv = BER_BVC("1"), *old;
+               
+               old = op->o_sync_state.ctxcsn;
+               op->o_sync_state.ctxcsn = &bv;
+               syncprov_findcsn( op, FIND_CSN );
+               op->o_sync_state.ctxcsn = old;
+       }
 
-static int
-syncprov_op_search( Operation *op, SlapReply *rs )
-{
+       /* Append CSN range to search filter */
+       op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
+
+       fand = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
+       fand->f_choice = LDAP_FILTER_AND;
+       fand->f_next = NULL;
+       fava = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
+       fava->f_choice = LDAP_FILTER_LE;
+       fava->f_ava = op->o_tmpalloc( sizeof(AttributeAssertion), op->o_tmpmemctx );
+       fava->f_ava->aa_desc = slap_schema.si_ad_entryCSN;
+       ber_dupbv_x( &fava->f_ava->aa_value, &si->si_ctxcsn, op->o_tmpmemctx );
+       fand->f_and = fava;
+       if ( gotstate ) {
+               fava->f_next = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
+               fava = fava->f_next;
+               fava->f_choice = LDAP_FILTER_GE;
+               fava->f_ava = op->o_tmpalloc( sizeof(AttributeAssertion), op->o_tmpmemctx );
+               fava->f_ava->aa_desc = slap_schema.si_ad_entryCSN;
+               ber_dupbv_x( &fava->f_ava->aa_value, op->o_sync_state.ctxcsn, op->o_tmpmemctx );
+       }
+       fava->f_next = op->ors_filter;
+       op->ors_filter = fand;
+       filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
+
+       /* Let our callback add needed info to returned entries */
+       cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(opcookie), op->o_tmpmemctx);
+       cb->sc_response = syncprov_search_response;
+       cb->sc_cleanup = syncprov_search_cleanup;
+       cb->sc_private = on;
+       cb->sc_next = op->o_callback;
+       op->o_callback = cb;
+
+       return SLAP_CB_CONTINUE;
 }
 
+#if 0
 static int
 syncprov_response( Operation *op, SlapReply *rs )
 {
        slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
        syncprov_info_t         *si = (syncprov_info_t *)on->on_bi.bi_private;
 
-       /* If the operation succeeded and we're checkpointing */
-       if ( rs->sr_err == LDAP_SUCCESS && ( si->si_chkops || si->si_chktime ))
-       {
-               int do_check = 0;
+       if ( rs->sr_err == LDAP_SUCCESS ) {
+               if ( op->o_tag == LDAP_REQ_SEARCH ) {
+                       /* handle transition from refresh to persist */
+                       if ( op->o_sync_mode == SLAP_SYNC_REFRESH_AND_PERSIST ) {
+                       }
 
-               switch ( op->o_tag ) {
-               case LDAP_REQ_EXTENDED:
-                       { int i, doit = 0;
+               /* If we're checkpointing */
+               } else if ( si->si_chkops || si->si_chktime )) {
+                       int do_check = 0;
 
-                       /* if not PASSWD_MODIFY, break */
-                       for ( i=0; write_exop[i]; i++ )
-                       {
-                               if ( !ber_bvcmp( write_exop[i], &op->oq_extended.rs_reqoid ))
+                       switch ( op->o_tag ) {
+                       case LDAP_REQ_EXTENDED:
+                               { int i, doit = 0;
+
+                               /* if not PASSWD_MODIFY, break */
+                               for ( i=0; write_exop[i]; i++ )
                                {
-                                       doit = 1;
-                                       break;
+                                       if ( !ber_bvcmp( write_exop[i], &op->oq_extended.rs_reqoid ))
+                                       {
+                                               doit = 1;
+                                               break;
+                                       }
                                }
-                       }
-                       if ( !doit ) break;
-                       }
-                       /* else fallthru */
-               case LDAP_REQ_ADD:
-               case LDAP_REQ_MODIFY:
-               case LDAP_REQ_MODRDN:
-               case LDAP_REQ_DELETE:
-                       ldap_pvt_thread_mutex_lock( &si->si_chk_mutex );
-                       if ( si->si_chkops )
-                       {
-                               si->si_numops++;
-                               if ( si->si_numops >= si->si_chkops )
+                               if ( !doit ) break;
+                               }
+                               /* else fallthru */
+                       case LDAP_REQ_ADD:
+                       case LDAP_REQ_MODIFY:
+                       case LDAP_REQ_MODRDN:
+                       case LDAP_REQ_DELETE:
+                               ldap_pvt_thread_mutex_lock( &si->si_chk_mutex );
+                               if ( si->si_chkops )
                                {
-                                       do_check = 1;
-                                       si->si_numops = 0;
+                                       si->si_numops++;
+                                       if ( si->si_numops >= si->si_chkops )
+                                       {
+                                               do_check = 1;
+                                               si->si_numops = 0;
+                                       }
                                }
-                       }
-                       if ( si->si_chktime )
-                       {
-                               if ( op->o_time - si->si_chklast >= si->si_chktime )
+                               if ( si->si_chktime )
                                {
-                                       do_check = 1;
-                                       si->si_chklast = op->o_time;
+                                       if ( op->o_time - si->si_chklast >= si->si_chktime )
+                                       {
+                                               do_check = 1;
+                                               si->si_chklast = op->o_time;
+                                       }
                                }
+                               ldap_pvt_thread_mutex_unlock( &si->si_chk_mutex );
+                               if ( do_check )
+                               {
+                                       /* write cn=ldapsync to underlying db */
+                               }
+                               break;
                        }
-                       ldap_pvt_thread_mutex_unlock( &si->si_chk_mutex );
-                       if ( do_check )
-                       {
-                               /* write cn=ldapsync to underlying db */
-                       }
-                       break;
                }
        }
+       /* Release this DN */
+       if ( op->o_tag == LDAP_REQ_MODIFY ) {
+               ldap_pvt_thread_mutex_lock( &si->si_mod_mutex );
+               avl_delete( &si->si_mods, &op->o_req_ndn, dn_avl_cmp );
+               ldap_pvt_thread_mutex_unlock( &si->si_mod_mutex );
+       }
        return SLAP_CB_CONTINUE;
 }
+#endif
 
 static int
 syncprov_db_config(
@@ -466,10 +756,11 @@ syncprov_db_config(
        slap_overinst           *on = (slap_overinst *)be->bd_info;
        syncprov_info_t         *si = (syncprov_info_t *)on->on_bi.bi_private;
 
+#if 0
        if ( strcasecmp( argv[ 0 ], "syncprov-checkpoint" ) == 0 ) {
                if ( argc != 3 ) {
                        fprintf( stderr, "%s: line %d: wrong number of arguments in "
-                               "\"syncprov-checkpint <ops> <minutes>\"\n", fname, lineno );
+                               "\"syncprov-checkpoint <ops> <minutes>\"\n", fname, lineno );
                        return -1;
                }
                si->si_chkops = atoi( argv[1] );
@@ -478,40 +769,9 @@ syncprov_db_config(
        } else {
                return SLAP_CONF_UNKNOWN;
        }
+#endif
 
-       return 0;
-}
-
-/* Read any existing cn=ldapsync context from the underlying db.
- * Then search for any entries newer than that. If no value exists,
- * just generate it. Cache whatever result.
- */
-static int
-syncprov_db_open(
-       BackendDB *be
-)
-{
-       slap_overinst   *on = (slap_overinst *) be->bd_info;
-       syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
-
-       return 0;
-}
-
-/* Write the current cn=ldapsync context into the underlying db.
- */
-static int
-syncprov_db_close(
-       BackendDB *be
-)
-{
-       slap_overinst   *on = (slap_overinst *) be->bd_info;
-       syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
-
-       /* for si->si_ops:
-        *   send DONE messages
-        *   free si_ops
-        */
-       return 0;
+       return SLAP_CONF_UNKNOWN;
 }
 
 static int
@@ -524,10 +784,14 @@ syncprov_db_init(
 
        si = ch_calloc(1, sizeof(syncprov_info_t));
        on->on_bi.bi_private = si;
-
-       ldap_pvt_thread_mutex_init( &si->si_e_mutex );
+       ldap_pvt_thread_mutex_init( &si->si_csn_mutex );
        ldap_pvt_thread_mutex_init( &si->si_ops_mutex );
-       ldap_pvt_thread_mutex_init( &si->si_chk_mutex );
+
+       csn_anlist[0].an_desc = slap_schema.si_ad_entryCSN;
+       csn_anlist[0].an_name = slap_schema.si_ad_entryCSN->ad_cname;
+
+       uuid_anlist[0].an_desc = slap_schema.si_ad_entryUUID;
+       uuid_anlist[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
 
        return 0;
 }
@@ -541,14 +805,8 @@ syncprov_db_destroy(
        syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
 
        if ( si ) {
-               if ( si->si_e ) {
-                       entry_free( si->si_e );
-
-               }
-               ldap_pvt_thread_mutex_destroy( &si->si_chk_mutex );
                ldap_pvt_thread_mutex_destroy( &si->si_ops_mutex );
-               ldap_pvt_thread_mutex_destroy( &si->si_e_mutex );
-
+               ldap_pvt_thread_mutex_destroy( &si->si_csn_mutex );
                ch_free( si );
        }
 
@@ -569,18 +827,20 @@ syncprov_init()
        syncprov.on_bi.bi_db_init = syncprov_db_init;
        syncprov.on_bi.bi_db_config = syncprov_db_config;
        syncprov.on_bi.bi_db_destroy = syncprov_db_destroy;
-       syncprov.on_bi.bi_db_open = syncprov_db_open;
-       syncprov.on_bi.bi_db_close = syncprov_db_close;
 
-       syncprov.on_bi.bi_op_add = syncprov_op_add;
+       syncprov.on_bi.bi_op_add = syncprov_op_mod;
+#if 0
        syncprov.on_bi.bi_op_compare = syncprov_op_compare;
-       syncprov.on_bi.bi_op_delete = syncprov_op_delete;
-       syncprov.on_bi.bi_op_modify = syncprov_op_modify;
-       syncprov.on_bi.bi_op_modrdn = syncprov_op_modrdn;
+#endif
+       syncprov.on_bi.bi_op_delete = syncprov_op_mod;
+       syncprov.on_bi.bi_op_modify = syncprov_op_mod;
+       syncprov.on_bi.bi_op_modrdn = syncprov_op_mod;
        syncprov.on_bi.bi_op_search = syncprov_op_search;
        syncprov.on_bi.bi_extended = syncprov_op_extended;
 
+#if 0
        syncprov.on_response = syncprov_response;
+#endif
 
        return overlay_register( &syncprov );
 }