📄 syncprov.c
字号:
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/syncprov.c,v 1.56.2.42 2007/02/07 01:51:36 hyc Exp $ *//* syncprov.c - syncrepl provider *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 2004-2007 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. *//* ACKNOWLEDGEMENTS: * This work was initially developed by Howard Chu for inclusion in * OpenLDAP Software. */#include "portable.h"#ifdef SLAPD_OVER_SYNCPROV#include <ac/string.h>#include "lutil.h"#include "slap.h"#include "config.h"#include "ldap_rq.h"/* A modify request on a particular entry */typedef struct modinst { struct modinst *mi_next; Operation *mi_op;} modinst;typedef struct modtarget { struct modinst *mt_mods; struct modinst *mt_tail; Operation *mt_op; ldap_pvt_thread_mutex_t mt_mutex;} modtarget;/* A queued result of a persistent search */typedef struct syncres { struct syncres *s_next; struct berval s_dn; struct berval s_ndn; struct berval s_uuid; struct berval s_csn; char s_mode; char s_isreference;} syncres;/* Record of a persistent search */typedef struct syncops { struct syncops *s_next; struct berval s_base; /* ndn of search base */ ID s_eid; /* entryID of search base */ Operation *s_op; /* search op */ int s_rid; struct berval s_filterstr; int s_flags; /* search status */#define PS_IS_REFRESHING 0x01#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; struct syncres *s_restail; struct re_s *s_qtask; /* task for playing psearch responses */#define RUNQ_INTERVAL 36000 /* a long time */ ldap_pvt_thread_mutex_t s_mutex;} syncops;/* A received sync control */typedef struct sync_control { struct sync_cookie sr_state; int sr_rhint;} sync_control;#if 0 /* moved back to slap.h */#define o_sync o_ctrlflag[slap_cids.sc_LDAPsync]#endif/* o_sync_mode uses data bits of o_sync */#define o_sync_mode o_ctrlflag[slap_cids.sc_LDAPsync]#define SLAP_SYNC_NONE (LDAP_SYNC_NONE<<SLAP_CONTROL_SHIFT)#define SLAP_SYNC_REFRESH (LDAP_SYNC_REFRESH_ONLY<<SLAP_CONTROL_SHIFT)#define SLAP_SYNC_PERSIST (LDAP_SYNC_RESERVED<<SLAP_CONTROL_SHIFT)#define SLAP_SYNC_REFRESH_AND_PERSIST (LDAP_SYNC_REFRESH_AND_PERSIST<<SLAP_CONTROL_SHIFT)/* Record of which searches matched at premodify step */typedef struct syncmatches { struct syncmatches *sm_next; syncops *sm_op;} syncmatches;/* Session log data */typedef struct slog_entry { struct slog_entry *se_next; struct berval se_uuid; struct berval se_csn; ber_tag_t se_tag;} slog_entry;typedef struct sessionlog { struct berval sl_mincsn; int sl_num; int sl_size; slog_entry *sl_head; slog_entry *sl_tail; ldap_pvt_thread_mutex_t sl_mutex;} sessionlog;/* The main state for this overlay */typedef struct syncprov_info_t { syncops *si_ops; struct berval si_ctxcsn; /* ldapsync context */ int si_chkops; /* checkpointing info */ int si_chktime; int si_numops; /* number of ops since last checkpoint */ int si_nopres; /* Skip present phase */ int si_usehint; /* use reload hint */ time_t si_chklast; /* time of last checkpoint */ Avlnode *si_mods; /* entries being modified */ sessionlog *si_logs; ldap_pvt_thread_rdwr_t si_csn_rwlock; ldap_pvt_thread_mutex_t si_ops_mutex; ldap_pvt_thread_mutex_t si_mods_mutex; char si_ctxcsnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];} syncprov_info_t;typedef struct opcookie { slap_overinst *son; syncmatches *smatches; struct berval sdn; /* DN of entry, for deletes */ struct berval sndn; struct berval suuid; /* UUID of entry */ struct berval sctxcsn; int sreference; /* Is the entry a reference? */} opcookie;typedef struct fbase_cookie { struct berval *fdn; /* DN of a modified entry, for scope testing */ syncops *fss; /* persistent search we're testing against */ int fbase; /* if TRUE we found the search base and it's still valid */ int fscope; /* if TRUE then fdn is within the psearch scope */} fbase_cookie;static AttributeName csn_anlist[3];static AttributeName uuid_anlist[2];/* Build a LDAPsync intermediate state control */static intsyncprov_state_ctrl( Operation *op, SlapReply *rs, Entry *e, int entry_sync_state, LDAPControl **ctrls, int num_ctrls, int send_cookie, struct berval *cookie ){ Attribute* a; int ret; BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; struct berval entryuuid_bv = BER_BVNULL; ber_init2( ber, 0, LBER_USE_DER ); ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); ctrls[num_ctrls] = op->o_tmpalloc( sizeof ( LDAPControl ), op->o_tmpmemctx ); for ( a = e->e_attrs; a != NULL; a = a->a_next ) { AttributeDescription *desc = a->a_desc; if ( desc == slap_schema.si_ad_entryUUID ) { entryuuid_bv = a->a_nvals[0]; break; } } /* FIXME: what if entryuuid is NULL or empty ? */ if ( send_cookie && cookie ) { ber_printf( ber, "{eOON}", entry_sync_state, &entryuuid_bv, cookie ); } else { ber_printf( ber, "{eON}", entry_sync_state, &entryuuid_bv ); } ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_STATE; ctrls[num_ctrls]->ldctl_iscritical = (op->o_sync == SLAP_CONTROL_CRITICAL); ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); ber_free_buf( ber ); if ( ret < 0 ) { Debug( LDAP_DEBUG_TRACE, "slap_build_sync_ctrl: ber_flatten2 failed\n", 0, 0, 0 ); send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); return ret; } return LDAP_SUCCESS;}/* Build a LDAPsync final state control */static intsyncprov_done_ctrl( Operation *op, SlapReply *rs, LDAPControl **ctrls, int num_ctrls, int send_cookie, struct berval *cookie, int refreshDeletes ){ int ret; BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; ber_init2( ber, NULL, LBER_USE_DER ); ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); ctrls[num_ctrls] = op->o_tmpalloc( sizeof ( LDAPControl ), op->o_tmpmemctx ); ber_printf( ber, "{" ); if ( send_cookie && cookie ) { ber_printf( ber, "O", cookie ); } if ( refreshDeletes == LDAP_SYNC_REFRESH_DELETES ) { ber_printf( ber, "b", refreshDeletes ); } ber_printf( ber, "N}" ); ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_DONE; ctrls[num_ctrls]->ldctl_iscritical = (op->o_sync == SLAP_CONTROL_CRITICAL); ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); ber_free_buf( ber ); if ( ret < 0 ) { Debug( LDAP_DEBUG_TRACE, "syncprov_done_ctrl: ber_flatten2 failed\n", 0, 0, 0 ); send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); return ret; } return LDAP_SUCCESS;}static intsyncprov_sendinfo( Operation *op, SlapReply *rs, int type, struct berval *cookie, int refreshDone, BerVarray syncUUIDs, int refreshDeletes ){ BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; struct berval rspdata; int ret; ber_init2( ber, NULL, LBER_USE_DER ); ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); if ( type ) { switch ( type ) { case LDAP_TAG_SYNC_NEW_COOKIE: ber_printf( ber, "tO", type, cookie ); break; case LDAP_TAG_SYNC_REFRESH_DELETE: case LDAP_TAG_SYNC_REFRESH_PRESENT: ber_printf( ber, "t{", type ); if ( cookie ) { ber_printf( ber, "O", cookie ); } if ( refreshDone == 0 ) { ber_printf( ber, "b", refreshDone ); } ber_printf( ber, "N}" ); break; case LDAP_TAG_SYNC_ID_SET: ber_printf( ber, "t{", type ); if ( cookie ) { ber_printf( ber, "O", cookie ); } if ( refreshDeletes == 1 ) { ber_printf( ber, "b", refreshDeletes ); } ber_printf( ber, "[W]", syncUUIDs ); ber_printf( ber, "N}" ); break; default: Debug( LDAP_DEBUG_TRACE, "syncprov_sendinfo: invalid syncinfo type (%d)\n", type, 0, 0 ); return LDAP_OTHER; } } ret = ber_flatten2( ber, &rspdata, 0 ); if ( ret < 0 ) { Debug( LDAP_DEBUG_TRACE, "syncprov_sendinfo: ber_flatten2 failed\n", 0, 0, 0 ); send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); return ret; } rs->sr_rspoid = LDAP_SYNC_INFO; rs->sr_rspdata = &rspdata; send_ldap_intermediate( op, rs ); rs->sr_rspdata = NULL; ber_free_buf( ber ); return LDAP_SUCCESS;}/* Find a modtarget in an AVL tree */static intsp_avl_cmp( const void *c1, const void *c2 ){ const modtarget *m1, *m2; int rc; m1 = c1; m2 = c2; rc = m1->mt_op->o_req_ndn.bv_len - m2->mt_op->o_req_ndn.bv_len; if ( rc ) return rc; return ber_bvcmp( &m1->mt_op->o_req_ndn, &m2->mt_op->o_req_ndn );}/* syncprov_findbase: * finds the true DN of the base of a search (with alias dereferencing) and * checks to make sure the base entry doesn't get replaced with a different * entry (e.g., swapping trees via ModDN, or retargeting an alias). If a * change is detected, any persistent search on this base must be terminated / * reloaded. * On the first call, we just save the DN and entryID. On subsequent calls * we compare the DN and entryID with the saved values. */static intfindbase_cb( Operation *op, SlapReply *rs ){ slap_callback *sc = op->o_callback; if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) { fbase_cookie *fc = sc->sc_private; /* If no entryID, we're looking for the first time. * Just store whatever we got. */ if ( fc->fss->s_eid == NOID ) { fc->fbase = 2; fc->fss->s_eid = rs->sr_entry->e_id; ber_dupbv( &fc->fss->s_base, &rs->sr_entry->e_nname ); } else if ( rs->sr_entry->e_id == fc->fss->s_eid && dn_match( &rs->sr_entry->e_nname, &fc->fss->s_base )) { /* OK, the DN is the same and the entryID is the same. */ fc->fbase = 1; } } if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "findbase failed! %d\n", rs->sr_err,0,0 ); } return LDAP_SUCCESS;}static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL };static struct berval generic_filterstr = BER_BVC("(objectclass=*)");static intsyncprov_findbase( Operation *op, fbase_cookie *fc ){ opcookie *opc = op->o_callback->sc_private; slap_overinst *on = opc->son; /* Use basic parameters from syncrepl search, but use * current op's threadctx / tmpmemctx */ ldap_pvt_thread_mutex_lock( &fc->fss->s_mutex ); if ( fc->fss->s_flags & PS_FIND_BASE ) { slap_callback cb = {0}; Operation fop; SlapReply frs = { REP_RESULT }; int rc; fc->fss->s_flags ^= PS_FIND_BASE; ldap_pvt_thread_mutex_unlock( &fc->fss->s_mutex ); fop = *fc->fss->s_op; fop.o_hdr = op->o_hdr; fop.o_bd = op->o_bd; fop.o_time = op->o_time; fop.o_tincr = op->o_tincr; cb.sc_response = findbase_cb; cb.sc_private = fc; fop.o_sync_mode = 0; /* turn off sync mode */ fop.o_managedsait = SLAP_CONTROL_CRITICAL; fop.o_callback = &cb; fop.o_tag = LDAP_REQ_SEARCH; fop.ors_scope = LDAP_SCOPE_BASE; fop.ors_limit = NULL; fop.ors_slimit = 1; fop.ors_tlimit = SLAP_NO_LIMIT; fop.ors_attrs = slap_anlist_no_attrs; fop.ors_attrsonly = 1; fop.ors_filter = &generic_filter; fop.ors_filterstr = generic_filterstr; fop.o_bd->bd_info = on->on_info->oi_orig; rc = fop.o_bd->be_search( &fop, &frs ); fop.o_bd->bd_info = (BackendInfo *)on; } else { ldap_pvt_thread_mutex_unlock( &fc->fss->s_mutex ); fc->fbase = 1; } /* After the first call, see if the fdn resides in the scope */ if ( fc->fbase == 1 ) { switch ( fc->fss->s_op->ors_scope ) { case LDAP_SCOPE_BASE: fc->fscope = dn_match( fc->fdn, &fc->fss->s_base ); break; case LDAP_SCOPE_ONELEVEL: { struct berval pdn; dnParent( fc->fdn, &pdn ); fc->fscope = dn_match( &pdn, &fc->fss->s_base ); break; } case LDAP_SCOPE_SUBTREE: fc->fscope = dnIsSuffix( fc->fdn, &fc->fss->s_base ); break; case LDAP_SCOPE_SUBORDINATE: fc->fscope = dnIsSuffix( fc->fdn, &fc->fss->s_base ) && !dn_match( fc->fdn, &fc->fss->s_base ); break; } } if ( fc->fbase ) return LDAP_SUCCESS; /* If entryID has changed, then the base of this search has * changed. Invalidate the psearch. */ return LDAP_NO_SUCH_OBJECT;}/* syncprov_findcsn: * This function has three different purposes, but they all use a search * that filters on entryCSN so they're combined here. * 1: at startup time, after a contextCSN has been read from the database, * we search for all entries with CSN >= contextCSN in case the contextCSN * was not checkpointed at the previous shutdown. * * 2: when the current contextCSN is known and we have a sync cookie, we search * for one entry with CSN = the cookie CSN. If not found, try <= cookie CSN. * If an entry is found, the cookie CSN is valid, otherwise it is stale. * * 3: during a refresh phase, we search for all entries with CSN <= the cookie * CSN, and generate Present records for them. We always collect this result * in SyncID sets, even if there's only one match. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -