X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Foverlays%2Fsyncprov.c;h=db037774693f70488de90fee7b11bcf17ee6302a;hb=34f4c2cb97dd6c7851e30298c7e014e170f54665;hp=b4c42c3f52d7f0c1cda3877e63fd4100b09431e0;hpb=ed2f5c565cac14d452d4de77eb72257e11ebe789;p=openldap diff --git a/servers/slapd/overlays/syncprov.c b/servers/slapd/overlays/syncprov.c index b4c42c3f52..db03777469 100644 --- a/servers/slapd/overlays/syncprov.c +++ b/servers/slapd/overlays/syncprov.c @@ -65,6 +65,7 @@ typedef struct syncops { #define PS_IS_DETACHED 0x02 #define PS_WROTE_BASE 0x04 #define PS_FIND_BASE 0x08 +#define PS_FIX_FILTER 0x10 int s_inuse; /* reference count */ struct syncres *s_res; @@ -911,6 +912,33 @@ syncprov_qtask( void *ctx, void *arg ) return NULL; } +/* Start the task to play back queued psearch responses */ +static void +syncprov_qstart( syncops *so ) +{ + int wake=0; + ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); + if ( !so->s_qtask ) { + so->s_qtask = ldap_pvt_runqueue_insert( &slapd_rq, RUNQ_INTERVAL, + syncprov_qtask, so, "syncprov_qtask", + so->s_op->o_conn->c_peer_name.bv_val ); + ++so->s_inuse; + wake = 1; + } else { + if (!ldap_pvt_runqueue_isrunning( &slapd_rq, so->s_qtask ) && + !so->s_qtask->next_sched.tv_sec ) { + so->s_qtask->interval.tv_sec = 0; + ldap_pvt_runqueue_resched( &slapd_rq, so->s_qtask, 0 ); + so->s_qtask->interval.tv_sec = RUNQ_INTERVAL; + ++so->s_inuse; + wake = 1; + } + } + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); + if ( wake ) + slap_wake_listener(); +} + /* Queue a persistent search response */ static int syncprov_qresp( opcookie *opc, syncops *so, int mode ) @@ -949,27 +977,7 @@ syncprov_qresp( opcookie *opc, syncops *so, int mode ) so->s_flags |= PS_FIND_BASE; } if ( so->s_flags & PS_IS_DETACHED ) { - int wake=0; - ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); - if ( !so->s_qtask ) { - so->s_qtask = ldap_pvt_runqueue_insert( &slapd_rq, RUNQ_INTERVAL, - syncprov_qtask, so, "syncprov_qtask", - so->s_op->o_conn->c_peer_name.bv_val ); - ++so->s_inuse; - wake = 1; - } else { - if (!ldap_pvt_runqueue_isrunning( &slapd_rq, so->s_qtask ) && - !so->s_qtask->next_sched.tv_sec ) { - so->s_qtask->interval.tv_sec = 0; - ldap_pvt_runqueue_resched( &slapd_rq, so->s_qtask, 0 ); - so->s_qtask->interval.tv_sec = RUNQ_INTERVAL; - ++so->s_inuse; - wake = 1; - } - } - ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); - if ( wake ) - slap_wake_listener(); + syncprov_qstart( so ); } ldap_pvt_thread_mutex_unlock( &so->s_mutex ); return LDAP_SUCCESS; @@ -1055,6 +1063,7 @@ syncprov_matchops( Operation *op, opcookie *opc, int saveit ) int rc; struct berval newdn; int freefdn = 0; + BackendDB *b0 = op->o_bd, db; fc.fdn = &op->o_req_ndn; /* compute new DN */ @@ -1067,6 +1076,10 @@ syncprov_matchops( Operation *op, opcookie *opc, int saveit ) freefdn = 1; } if ( op->o_tag != LDAP_REQ_ADD ) { + if ( !SLAP_ISOVERLAY( op->o_bd )) { + db = *op->o_bd; + op->o_bd = &db; + } op->o_bd->bd_info = (BackendInfo *)on->on_info; rc = be_entry_get_rw( op, fc.fdn, NULL, NULL, 0, &e ); /* If we're sending responses now, make a copy and unlock the DB */ @@ -1076,7 +1089,10 @@ syncprov_matchops( Operation *op, opcookie *opc, int saveit ) e = e2; } op->o_bd->bd_info = (BackendInfo *)on; - if ( rc ) return; + if ( rc ) { + op->o_bd = b0; + return; + } } else { e = op->ora_e; } @@ -1174,6 +1190,7 @@ syncprov_matchops( Operation *op, opcookie *opc, int saveit ) if ( freefdn ) { op->o_tmpfree( fc.fdn->bv_val, op->o_tmpmemctx ); } + op->o_bd = b0; } static int @@ -1235,9 +1252,14 @@ syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on ) struct berval bv[2]; slap_callback cb = {0}; - mod.sml_values = bv; - bv[1].bv_val = NULL; - bv[0] = si->si_ctxcsn; + /* If ctxcsn is empty, delete it */ + if ( BER_BVISEMPTY( &si->si_ctxcsn )) { + mod.sml_values = NULL; + } else { + mod.sml_values = bv; + bv[1].bv_val = NULL; + bv[0] = si->si_ctxcsn; + } mod.sml_nvalues = NULL; mod.sml_desc = slap_schema.si_ad_contextCSN; mod.sml_op = LDAP_MOD_REPLACE; @@ -1262,7 +1284,7 @@ syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on ) } static void -syncprov_add_slog( Operation *op, struct berval *csn ) +syncprov_add_slog( Operation *op ) { opcookie *opc = op->o_callback->sc_private; slap_overinst *on = opc->son; @@ -1274,7 +1296,7 @@ syncprov_add_slog( Operation *op, struct berval *csn ) { /* Allocate a record. UUIDs are not NUL-terminated. */ se = ch_malloc( sizeof( slog_entry ) + opc->suuid.bv_len + - csn->bv_len + 1 ); + op->o_csn.bv_len + 1 ); se->se_next = NULL; se->se_tag = op->o_tag; @@ -1283,9 +1305,9 @@ syncprov_add_slog( Operation *op, struct berval *csn ) se->se_uuid.bv_len = opc->suuid.bv_len; se->se_csn.bv_val = se->se_uuid.bv_val + opc->suuid.bv_len; - AC_MEMCPY( se->se_csn.bv_val, csn->bv_val, csn->bv_len ); - se->se_csn.bv_val[csn->bv_len] = '\0'; - se->se_csn.bv_len = csn->bv_len; + AC_MEMCPY( se->se_csn.bv_val, op->o_csn.bv_val, op->o_csn.bv_len ); + se->se_csn.bv_val[op->o_csn.bv_len] = '\0'; + se->se_csn.bv_len = op->o_csn.bv_len; ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); if ( sl->sl_head ) { @@ -1320,12 +1342,14 @@ playlog_cb( Operation *op, SlapReply *rs ) /* enter with sl->sl_mutex locked, release before returning */ static void syncprov_playlog( Operation *op, SlapReply *rs, sessionlog *sl, - struct berval *oldcsn, struct berval *ctxcsn ) + sync_control *srs, struct berval *ctxcsn ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; slog_entry *se; int i, j, ndel, num, nmods, mmods; + char cbuf[LDAP_LUTIL_CSNSTR_BUFSIZE]; BerVarray uuids; + struct berval delcsn; if ( !sl->sl_num ) { ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); @@ -1338,19 +1362,24 @@ syncprov_playlog( Operation *op, SlapReply *rs, sessionlog *sl, uuids = op->o_tmpalloc( (num+1) * sizeof( struct berval ) + num * UUID_LEN, op->o_tmpmemctx ); - uuids[0].bv_val = (char *)(uuids + num + 1); + delcsn.bv_len = 0; + delcsn.bv_val = cbuf; + /* Make a copy of the relevant UUIDs. Put the Deletes up front * and everything else at the end. Do this first so we can * unlock the list mutex. */ for ( se=sl->sl_head; se; se=se->se_next ) { - if ( ber_bvcmp( &se->se_csn, oldcsn ) <= 0 ) continue; + if ( ber_bvcmp( &se->se_csn, &srs->sr_state.ctxcsn ) <= 0 ) continue; if ( ber_bvcmp( &se->se_csn, ctxcsn ) > 0 ) break; if ( se->se_tag == LDAP_REQ_DELETE ) { j = i; i++; + AC_MEMCPY( cbuf, se->se_csn.bv_val, se->se_csn.bv_len ); + delcsn.bv_len = se->se_csn.bv_len; + delcsn.bv_val[delcsn.bv_len] = '\0'; } else { nmods++; j = num - nmods; @@ -1442,9 +1471,14 @@ syncprov_playlog( Operation *op, SlapReply *rs, sessionlog *sl, fop.o_bd->bd_info = (BackendInfo *)on; } if ( ndel ) { + struct berval cookie; + + slap_compose_sync_cookie( op, &cookie, &delcsn, srs->sr_state.rid ); uuids[ndel].bv_val = NULL; - syncprov_sendinfo( op, rs, LDAP_TAG_SYNC_ID_SET, NULL, 0, uuids, 1 ); + syncprov_sendinfo( op, rs, LDAP_TAG_SYNC_ID_SET, &cookie, 0, uuids, 1 ); + op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); } + op->o_tmpfree( uuids, op->o_tmpmemctx ); } static int @@ -1457,13 +1491,13 @@ syncprov_op_response( Operation *op, SlapReply *rs ) if ( rs->sr_err == LDAP_SUCCESS ) { - struct berval maxcsn = BER_BVNULL, curcsn = BER_BVNULL; + struct berval maxcsn = BER_BVNULL; char cbuf[LDAP_LUTIL_CSNSTR_BUFSIZE]; /* Update our context CSN */ cbuf[0] = '\0'; ldap_pvt_thread_mutex_lock( &si->si_csn_mutex ); - slap_get_commit_csn( op, &maxcsn, &curcsn ); + slap_get_commit_csn( op, &maxcsn ); if ( !BER_BVISNULL( &maxcsn ) ) { strcpy( cbuf, maxcsn.bv_val ); if ( ber_bvcmp( &maxcsn, &si->si_ctxcsn ) > 0 ) { @@ -1524,7 +1558,7 @@ syncprov_op_response( Operation *op, SlapReply *rs ) /* Add any log records */ if ( si->si_logs && op->o_tag != LDAP_REQ_ADD ) { - syncprov_add_slog( op, &curcsn ); + syncprov_add_slog( op ); } } @@ -1759,7 +1793,15 @@ syncprov_detach_op( Operation *op, syncops *so, slap_overinst *on ) op2->ors_filterstr.bv_val = ptr; strcpy( ptr, so->s_filterstr.bv_val ); op2->ors_filterstr.bv_len = so->s_filterstr.bv_len; - op2->ors_filter = filter_dup( op->ors_filter, NULL ); + + /* Skip the AND/GE clause that we stuck on in front */ + if ( so->s_flags & PS_FIX_FILTER ) { + op2->ors_filter = op->ors_filter->f_and->f_next; + so->s_flags ^= PS_FIX_FILTER; + } else { + op2->ors_filter = op->ors_filter; + } + op2->ors_filter = filter_dup( op2->ors_filter, NULL ); so->s_op = op2; /* Copy any cached group ACLs individually */ @@ -1811,13 +1853,23 @@ syncprov_search_response( Operation *op, SlapReply *rs ) } if ( a ) { /* Make sure entry is less than the snapshot'd contextCSN */ - if ( ber_bvcmp( &a->a_nvals[0], &ss->ss_ctxcsn ) > 0 ) + if ( ber_bvcmp( &a->a_nvals[0], &ss->ss_ctxcsn ) > 0 ) { + Debug( LDAP_DEBUG_SYNC, "Entry %s CSN %s greater than snapshot %s\n", + rs->sr_entry->e_name.bv_val, + a->a_nvals[0].bv_val, + ss->ss_ctxcsn.bv_val ); return LDAP_SUCCESS; + } /* Don't send the ctx entry twice */ if ( !BER_BVISNULL( &srs->sr_state.ctxcsn ) && - bvmatch( &a->a_nvals[0], &srs->sr_state.ctxcsn ) ) + bvmatch( &a->a_nvals[0], &srs->sr_state.ctxcsn ) ) { + Debug( LDAP_DEBUG_SYNC, "Entry %s CSN %s matches ctx %s\n", + rs->sr_entry->e_name.bv_val, + a->a_nvals[0].bv_val, + srs->sr_state.ctxcsn.bv_val ); return LDAP_SUCCESS; + } } rs->sr_ctrls = op->o_tmpalloc( sizeof(LDAPControl *)*2, op->o_tmpmemctx ); @@ -1841,7 +1893,7 @@ syncprov_search_response( Operation *op, SlapReply *rs ) op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); } else { /* It's RefreshAndPersist, transition to Persist phase */ - syncprov_sendinfo( op, rs, ( ss->ss_present && rs->sr_nentries ) ? + syncprov_sendinfo( op, rs, ss->ss_present ? LDAP_TAG_SYNC_REFRESH_PRESENT : LDAP_TAG_SYNC_REFRESH_DELETE, &cookie, 1, NULL, 0 ); op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); @@ -1853,6 +1905,10 @@ syncprov_search_response( Operation *op, SlapReply *rs ) ss->ss_so->s_flags ^= PS_IS_REFRESHING; syncprov_detach_op( op, ss->ss_so, on ); + + /* If there are queued responses, fire them off */ + if ( ss->ss_so->s_res ) + syncprov_qstart( ss->ss_so ); ldap_pvt_thread_mutex_unlock( &ss->ss_so->s_mutex ); return LDAP_SUCCESS; @@ -1960,10 +2016,13 @@ syncprov_op_search( Operation *op, SlapReply *rs ) sl=si->si_logs; if ( sl ) { ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); - if ( ber_bvcmp( &srs->sr_state.ctxcsn, &sl->sl_mincsn ) >= 0 ) { + /* Are there any log entries, and is the consumer state + * present in the session log? + */ + if ( sl->sl_num > 0 && ber_bvcmp( &srs->sr_state.ctxcsn, &sl->sl_mincsn ) >= 0 ) { do_present = 0; /* mutex is unlocked in playlog */ - syncprov_playlog( op, rs, sl, &srs->sr_state.ctxcsn, &ctxcsn ); + syncprov_playlog( op, rs, sl, srs, &ctxcsn ); } else { ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); } @@ -2014,6 +2073,8 @@ shortcut: fava->f_next = op->ors_filter; op->ors_filter = fand; filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); + if ( sop ) + sop->s_flags |= PS_FIX_FILTER; } /* Let our callback add needed info to returned entries */ @@ -2296,6 +2357,12 @@ syncprov_db_open( int rc; void *thrctx = NULL; + if ( !SLAP_LASTMOD( be )) { + Debug( LDAP_DEBUG_ANY, + "syncprov_db_open: invalid config, lastmod must be enabled\n", 0, 0, 0 ); + return -1; + } + if ( slapMode & SLAP_TOOL_MODE ) { return 0; } @@ -2339,15 +2406,16 @@ syncprov_db_open( ldap_pvt_thread_create( &tid, 0, syncprov_db_otask, op ); ldap_pvt_thread_join( tid, NULL ); } - } else if ( SLAP_SYNC_SHADOW( op->o_bd )) { - /* If we're also a consumer, and we didn't find the context entry, - * then don't generate anything, wait for our provider to send it - * to us. - */ - goto out; } if ( BER_BVISEMPTY( &si->si_ctxcsn ) ) { + if ( SLAP_SYNC_SHADOW( op->o_bd )) { + /* If we're also a consumer, and we didn't get a contextCSN, + * then don't generate anything, wait for our provider to send it + * to us. + */ + goto out; + } si->si_ctxcsn.bv_len = sizeof( si->si_ctxcsnbuf ); slap_get_csn( op, &si->si_ctxcsn, 0 ); }