From 873a3c38fca9ebf462e6409ccfbeb6d8ceda91f0 Mon Sep 17 00:00:00 2001 From: Thierry Bordaz Date: Fri, 10 Nov 2017 10:44:55 +0100 Subject: [PATCH] Ticket 49446 - cleanallruv could break replication if startCsn originated from deleted replica Bug Description: Replication can break if the startCSN is missing in the changelog. This can occur because of changelog trimming. This is normal to break replication if startCSN is missing but if the startCSN belongs to a cleanAllRuv replica it is too bad considere it. Fix Description: when selecting the startCSN, it currently skips the csn from a cleared replica. The fix proposes a toggle in the replica entry (nsds5ReplicaIgnorePreClean). If it is set, when selecting the startCSN, it also skip the csn from the preClearer replicas (when cleanAllRuv for some reason does not complete) https://pagure.io/389-ds-base/issue/49446 Reviewed by: ? Platforms tested: F23 Flag Day: no Doc impact: no --- ldap/servers/plugins/replication/cl5_api.c | 8 +++++--- ldap/servers/plugins/replication/cl5_clcache.c | 7 +++++-- ldap/servers/plugins/replication/cl5_clcache.h | 2 +- ldap/servers/plugins/replication/repl5.h | 2 ++ ldap/servers/plugins/replication/repl5_replica.c | 25 +++++++++++++++++++++++- ldap/servers/plugins/replication/repl_globals.c | 1 + 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c index 58d13b3..3ebc074 100644 --- a/ldap/servers/plugins/replication/cl5_api.c +++ b/ldap/servers/plugins/replication/cl5_api.c @@ -5572,7 +5572,8 @@ static int _cl5PositionCursorForReplay (ReplicaId consumerRID, const RUV *consum Object *supplierRuvObj = NULL; RUV *supplierRuv = NULL; PRBool haveChanges = PR_FALSE; - char *agmt_name; + char *agmt_name; + Replica *r; PR_ASSERT (consumerRuv && replica && fileObj && iterator); csnStr[0] = '\0'; @@ -5580,7 +5581,8 @@ static int _cl5PositionCursorForReplay (ReplicaId consumerRID, const RUV *consum file = (CL5DBFile*)object_get_data (fileObj); /* get supplier's RUV */ - supplierRuvObj = replica_get_ruv((Replica*)object_get_data(replica)); + r = (Replica*)object_get_data(replica); + supplierRuvObj = replica_get_ruv(r); PR_ASSERT (supplierRuvObj); if (!supplierRuvObj) { @@ -5603,7 +5605,7 @@ static int _cl5PositionCursorForReplay (ReplicaId consumerRID, const RUV *consum /* initialize the changelog buffer and do the initial load */ - rc = clcache_get_buffer ( &clcache, file->db, consumerRID, consumerRuv, supplierRuv ); + rc = clcache_get_buffer ( &clcache, file->db, consumerRID, consumerRuv, supplierRuv, replica_get_ignorepreclean(r) ); if ( rc != 0 ) goto done; rc = clcache_load_buffer (clcache, &startCSN, continue_on_missing); diff --git a/ldap/servers/plugins/replication/cl5_clcache.c b/ldap/servers/plugins/replication/cl5_clcache.c index 5dda75d..24a2d27 100644 --- a/ldap/servers/plugins/replication/cl5_clcache.c +++ b/ldap/servers/plugins/replication/cl5_clcache.c @@ -73,6 +73,7 @@ struct clc_buffer { const RUV *buf_consumer_ruv; /* used to skip change */ const RUV *buf_local_ruv; /* used to refresh local_maxcsn */ int buf_ignoreConsumerRID; /* how to handle updates from consumer */ + int ignorePreClean; int buf_load_cnt; /* number of loads for session */ /* @@ -207,7 +208,7 @@ clcache_set_config () * a replication session. */ int -clcache_get_buffer ( CLC_Buffer **buf, DB *db, ReplicaId consumer_rid, const RUV *consumer_ruv, const RUV *local_ruv ) +clcache_get_buffer ( CLC_Buffer **buf, DB *db, ReplicaId consumer_rid, const RUV *consumer_ruv, const RUV *local_ruv, int ignorePreClean ) { int rc = 0; int need_new; @@ -259,6 +260,7 @@ clcache_get_buffer ( CLC_Buffer **buf, DB *db, ReplicaId consumer_rid, const RUV CSN *l_csn = NULL; (*buf)->buf_consumer_ruv = consumer_ruv; (*buf)->buf_local_ruv = local_ruv; + (*buf)->ignorePreClean = ignorePreClean; (*buf)->buf_load_flag = DB_MULTIPLE_KEY; ruv_get_largest_csn_for_replica (consumer_ruv, consumer_rid, &c_csn); ruv_get_largest_csn_for_replica (local_ruv, consumer_rid, &l_csn); @@ -563,7 +565,8 @@ clcache_refresh_local_maxcsn ( const ruv_enum_data *rid_data, void *data ) * and we ignore RID which have been cleaned */ if ( (rid == buf->buf_consumer_rid && buf->buf_ignoreConsumerRID) || - is_cleaned_rid(rid) ) + is_cleaned_rid(rid) || + (buf->ignorePreClean && is_pre_cleaned_rid(rid))) return rc; for ( i = 0; i < buf->buf_num_cscbs; i++ ) { diff --git a/ldap/servers/plugins/replication/cl5_clcache.h b/ldap/servers/plugins/replication/cl5_clcache.h index 9b6bbc8..a388f9f 100644 --- a/ldap/servers/plugins/replication/cl5_clcache.h +++ b/ldap/servers/plugins/replication/cl5_clcache.h @@ -22,7 +22,7 @@ typedef struct clc_buffer CLC_Buffer; int clcache_init ( DB_ENV **dbenv ); void clcache_set_config(void); -int clcache_get_buffer ( CLC_Buffer **buf, DB *db, ReplicaId consumer_rid, const RUV *consumer_ruv, const RUV *local_ruv ); +int clcache_get_buffer ( CLC_Buffer **buf, DB *db, ReplicaId consumer_rid, const RUV *consumer_ruv, const RUV *local_ruv, int ignorePreClean ); int clcache_load_buffer ( CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss ); void clcache_return_buffer ( CLC_Buffer **buf ); int clcache_get_next_change ( CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn ); diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h index 718f64e..47fa51f 100644 --- a/ldap/servers/plugins/replication/repl5.h +++ b/ldap/servers/plugins/replication/repl5.h @@ -183,6 +183,7 @@ extern const char *attr_replicaType; extern const char *attr_replicaBindDn; extern const char *attr_replicaBindDnGroup; extern const char *attr_replicaBindDnGroupCheckInterval; +extern const char *attr_replicaIgnorePreClean; extern const char *attr_state; extern const char *attr_flags; extern const char *attr_replicaName; @@ -604,6 +605,7 @@ void replica_set_referrals(Replica *r,const Slapi_ValueSet *vs); int replica_update_csngen_state (Replica *r, const RUV *ruv); int replica_update_csngen_state_ext (Replica *r, const RUV *ruv, const CSN *extracsn); CSN *replica_get_purge_csn(const Replica *r); +int replica_get_ignorepreclean(const Replica *r); int replica_log_ruv_elements (const Replica *r); void replica_enumerate_replicas (FNEnumReplica fn, void *arg); int replica_reload_ruv (Replica *r); diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c index fba755e..8d55904 100644 --- a/ldap/servers/plugins/replication/repl5_replica.c +++ b/ldap/servers/plugins/replication/repl5_replica.c @@ -45,6 +45,7 @@ struct replica { PRBool legacy_consumer; /* if true, this replica is supplied by 4.0 consumer */ char* legacy_purl; /* partial url of the legacy supplier */ ReplicaId repl_rid; /* replicaID */ + int ignorePreClean; Object *repl_ruv; /* replica update vector */ PRBool repl_ruv_dirty; /* Dirty flag for ruv */ CSNPL *min_csn_pl; /* Pending list for minimal CSN */ @@ -1557,6 +1558,19 @@ replica_get_purge_csn(const Replica *r) return csn; } +int +replica_get_ignorepreclean(const Replica *r) +{ + int preclean; + + replica_lock(r->repl_lock); + + preclean = r->ignorePreClean; + + replica_unlock(r->repl_lock); + + return preclean; +} /* * This function logs a dummy entry for the smallest csn in the RUV. @@ -2200,8 +2214,17 @@ _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext) "_replica_init_from_config - %s\n", errormsg); return -1; } - } + /* ignore preclean RUV */ + r->ignorePreClean = slapi_entry_attr_get_int( e, attr_replicaIgnorePreClean); + if(r->ignorePreClean){ + const char *repl_root; + repl_root = slapi_sdn_get_dn(r->repl_root); + slapi_log_err(SLAPI_LOG_WARNING, repl_plugin_name, + "_replica_init_from_config - %s will ignore pending cleanAllRuv RIDs\n", repl_root ? repl_root : ""); + + } + } attr = NULL; rc = slapi_entry_attr_find(e, attr_state, &attr); gen = csngen_new (r->repl_rid, attr); diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c index ab85e7f..91602fe 100644 --- a/ldap/servers/plugins/replication/repl_globals.c +++ b/ldap/servers/plugins/replication/repl_globals.c @@ -73,6 +73,7 @@ const char *attr_replicaType = "nsDS5ReplicaType"; const char *attr_replicaBindDn = "nsDS5ReplicaBindDn"; const char *attr_replicaBindDnGroup = "nsDS5ReplicaBindDnGroup"; const char *attr_replicaBindDnGroupCheckInterval = "nsDS5ReplicaBindDnGroupCheckInterval"; +const char *attr_replicaIgnorePreClean = "nsds5ReplicaIgnorePreClean"; const char *attr_state = "nsState"; const char *attr_flags = "nsds5Flags"; const char *attr_replicaName = "nsds5ReplicaName"; -- 2.5.5