|
|
081b2d |
From 127e0d954eb7741c4afdc0305f7970b7ea164e8d Mon Sep 17 00:00:00 2001
|
|
|
081b2d |
From: Ludwig Krispenz <lkrispen@redhat.com>
|
|
|
081b2d |
Date: Thu, 9 Nov 2017 11:28:34 +0100
|
|
|
081b2d |
Subject: [PATCH] Ticket 48118 - At startup, changelog can be erronously
|
|
|
081b2d |
rebuilt after a normal shutdown
|
|
|
081b2d |
|
|
|
081b2d |
Problem: There are two problems that can lead to inconsistent database and changelog maxruv:
|
|
|
081b2d |
1] the database ruv is written periodically in th ehouskeeping thread and at shutdown. It
|
|
|
081b2d |
relies on teh ruv_dirty flag, but due to a race condition this can be reset befor writing
|
|
|
081b2d |
the ruv
|
|
|
081b2d |
2] the changelog max ruv is updated whenever an operation is commutted, but in case of internal
|
|
|
081b2d |
operations inside the txn for a client operation, if the operation is aborted the cl maxruv
|
|
|
081b2d |
is not reset. Since it is only written at shutdown this normally is no problem, but if the
|
|
|
081b2d |
aborted operation is the last before shutdown or is aborted by shutdown the cl ruv is incorrect
|
|
|
081b2d |
|
|
|
081b2d |
Fix: the fix is in two parts:
|
|
|
081b2d |
1] remove the use of the dirty flag, ensure that the ruv is always written. The overhead for writing
|
|
|
081b2d |
a database ruv that has not changed is minimal
|
|
|
081b2d |
2] when writing the changelog maxruv check if the macsns it contains are really present in the
|
|
|
081b2d |
changelog. If not the maxruv is not written, it will be reconstructed at the next startup
|
|
|
081b2d |
|
|
|
081b2d |
Reviewed by: William,Thierry - Thanks
|
|
|
081b2d |
---
|
|
|
081b2d |
ldap/servers/plugins/replication/cl5_api.c | 39 ++++++++++++++++++++++
|
|
|
081b2d |
ldap/servers/plugins/replication/repl5.h | 1 -
|
|
|
081b2d |
ldap/servers/plugins/replication/repl5_replica.c | 32 +-----------------
|
|
|
081b2d |
.../plugins/replication/repl5_replica_config.c | 2 --
|
|
|
081b2d |
4 files changed, 40 insertions(+), 34 deletions(-)
|
|
|
081b2d |
|
|
|
081b2d |
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
|
|
|
081b2d |
index ec648c014..55032dfb0 100644
|
|
|
081b2d |
--- a/ldap/servers/plugins/replication/cl5_api.c
|
|
|
081b2d |
+++ b/ldap/servers/plugins/replication/cl5_api.c
|
|
|
081b2d |
@@ -250,6 +250,8 @@ static void _cl5ReadBerval(struct berval *bv, char **buff);
|
|
|
081b2d |
static void _cl5WriteBerval(struct berval *bv, char **buff);
|
|
|
081b2d |
static int _cl5ReadBervals(struct berval ***bv, char **buff, unsigned int size);
|
|
|
081b2d |
static int _cl5WriteBervals(struct berval **bv, char **buff, u_int32_t *size);
|
|
|
081b2d |
+static int64_t _cl5CheckMaxRUV(CL5DBFile *file, RUV *maxruv);
|
|
|
081b2d |
+static int64_t _cl5CheckCSNinCL(const ruv_enum_data *element, void *arg);
|
|
|
081b2d |
|
|
|
081b2d |
/* replay iteration */
|
|
|
081b2d |
#ifdef FOR_DEBUGGING
|
|
|
081b2d |
@@ -2716,6 +2718,36 @@ _cl5WriteBervals(struct berval **bv, char **buff, u_int32_t *size)
|
|
|
081b2d |
return CL5_SUCCESS;
|
|
|
081b2d |
}
|
|
|
081b2d |
|
|
|
081b2d |
+static int64_t
|
|
|
081b2d |
+_cl5CheckCSNinCL(const ruv_enum_data *element, void *arg)
|
|
|
081b2d |
+{
|
|
|
081b2d |
+ CL5DBFile *file = (CL5DBFile *)arg;
|
|
|
081b2d |
+ int rc = 0;
|
|
|
081b2d |
+
|
|
|
081b2d |
+ DBT key = {0}, data = {0};
|
|
|
081b2d |
+ char csnStr[CSN_STRSIZE];
|
|
|
081b2d |
+
|
|
|
081b2d |
+ /* construct the key */
|
|
|
081b2d |
+ key.data = csn_as_string(element->csn, PR_FALSE, csnStr);
|
|
|
081b2d |
+ key.size = CSN_STRSIZE;
|
|
|
081b2d |
+
|
|
|
081b2d |
+ data.flags = DB_DBT_MALLOC;
|
|
|
081b2d |
+
|
|
|
081b2d |
+ rc = file->db->get(file->db, NULL /*txn*/, &key, &data, 0);
|
|
|
081b2d |
+
|
|
|
081b2d |
+ slapi_ch_free(&(data.data));
|
|
|
081b2d |
+ return rc;
|
|
|
081b2d |
+}
|
|
|
081b2d |
+
|
|
|
081b2d |
+static int64_t
|
|
|
081b2d |
+_cl5CheckMaxRUV(CL5DBFile *file, RUV *maxruv)
|
|
|
081b2d |
+{
|
|
|
081b2d |
+ int rc = 0;
|
|
|
081b2d |
+
|
|
|
081b2d |
+ rc = ruv_enumerate_elements(maxruv, _cl5CheckCSNinCL, (void *)file);
|
|
|
081b2d |
+
|
|
|
081b2d |
+ return rc;
|
|
|
081b2d |
+}
|
|
|
081b2d |
/* upgrade from db33 to db41
|
|
|
081b2d |
* 1. Run recovery on the database environment using the DB_ENV->open method
|
|
|
081b2d |
* 2. Remove any Berkeley DB environment using the DB_ENV->remove method
|
|
|
081b2d |
@@ -4010,6 +4042,13 @@ _cl5WriteRUV(CL5DBFile *file, PRBool purge)
|
|
|
081b2d |
rc = ruv_to_bervals(file->maxRUV, &vals);
|
|
|
081b2d |
}
|
|
|
081b2d |
|
|
|
081b2d |
+ if (!purge && _cl5CheckMaxRUV(file, file->maxRUV)) {
|
|
|
081b2d |
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
|
|
|
081b2d |
+ "_cl5WriteRUV - changelog maxRUV not found in changelog for file %s\n",
|
|
|
081b2d |
+ file->name);
|
|
|
081b2d |
+ return CL5_DB_ERROR;
|
|
|
081b2d |
+ }
|
|
|
081b2d |
+
|
|
|
081b2d |
key.size = CSN_STRSIZE;
|
|
|
081b2d |
|
|
|
081b2d |
rc = _cl5WriteBervals(vals, &buff, &data.size);
|
|
|
081b2d |
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
|
|
|
081b2d |
index c6e79b7e2..4e206a0fc 100644
|
|
|
081b2d |
--- a/ldap/servers/plugins/replication/repl5.h
|
|
|
081b2d |
+++ b/ldap/servers/plugins/replication/repl5.h
|
|
|
081b2d |
@@ -725,7 +725,6 @@ Object *replica_get_for_backend(const char *be_name);
|
|
|
081b2d |
void replica_set_purge_delay(Replica *r, uint32_t purge_delay);
|
|
|
081b2d |
void replica_set_tombstone_reap_interval(Replica *r, long interval);
|
|
|
081b2d |
void replica_update_ruv_consumer(Replica *r, RUV *supplier_ruv);
|
|
|
081b2d |
-void replica_set_ruv_dirty(Replica *r);
|
|
|
081b2d |
Slapi_Entry *get_in_memory_ruv(Slapi_DN *suffix_sdn);
|
|
|
081b2d |
int replica_write_ruv(Replica *r);
|
|
|
081b2d |
char *replica_get_dn(Replica *r);
|
|
|
081b2d |
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
|
|
|
081b2d |
index e5296bf1c..77f4f18e4 100644
|
|
|
081b2d |
--- a/ldap/servers/plugins/replication/repl5_replica.c
|
|
|
081b2d |
+++ b/ldap/servers/plugins/replication/repl5_replica.c
|
|
|
081b2d |
@@ -41,7 +41,6 @@ struct replica
|
|
|
081b2d |
ReplicaType repl_type; /* is this replica read-only ? */
|
|
|
081b2d |
ReplicaId repl_rid; /* replicaID */
|
|
|
081b2d |
Object *repl_ruv; /* replica update vector */
|
|
|
081b2d |
- PRBool repl_ruv_dirty; /* Dirty flag for ruv */
|
|
|
081b2d |
CSNPL *min_csn_pl; /* Pending list for minimal CSN */
|
|
|
081b2d |
void *csn_pl_reg_id; /* registration assignment for csn callbacks */
|
|
|
081b2d |
unsigned long repl_state_flags; /* state flags */
|
|
|
081b2d |
@@ -788,7 +787,6 @@ replica_set_ruv(Replica *r, RUV *ruv)
|
|
|
081b2d |
}
|
|
|
081b2d |
|
|
|
081b2d |
r->repl_ruv = object_new((void *)ruv, (FNFree)ruv_destroy);
|
|
|
081b2d |
- r->repl_ruv_dirty = PR_TRUE;
|
|
|
081b2d |
|
|
|
081b2d |
replica_unlock(r->repl_lock);
|
|
|
081b2d |
}
|
|
|
081b2d |
@@ -860,9 +858,6 @@ replica_update_ruv(Replica *r, const CSN *updated_csn, const char *replica_purl)
|
|
|
081b2d |
"to update RUV for replica %s, csn = %s\n",
|
|
|
081b2d |
slapi_sdn_get_dn(r->repl_root),
|
|
|
081b2d |
csn_as_string(updated_csn, PR_FALSE, csn_str));
|
|
|
081b2d |
- } else {
|
|
|
081b2d |
- /* RUV updated - mark as dirty */
|
|
|
081b2d |
- r->repl_ruv_dirty = PR_TRUE;
|
|
|
081b2d |
}
|
|
|
081b2d |
} else {
|
|
|
081b2d |
slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
|
|
|
081b2d |
@@ -1347,8 +1342,6 @@ replica_dump(Replica *r)
|
|
|
081b2d |
slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "\tupdate dn: %s\n",
|
|
|
081b2d |
updatedn_list ? updatedn_list : "not configured");
|
|
|
081b2d |
slapi_ch_free_string(&updatedn_list);
|
|
|
081b2d |
- slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "\truv: %s configured and is %sdirty\n",
|
|
|
081b2d |
- r->repl_ruv ? "" : "not", r->repl_ruv_dirty ? "" : "not ");
|
|
|
081b2d |
slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "\tCSN generator: %s configured\n",
|
|
|
081b2d |
r->repl_csngen ? "" : "not");
|
|
|
081b2d |
/* JCMREPL - Dump Referrals */
|
|
|
081b2d |
@@ -1675,7 +1668,6 @@ replica_check_for_data_reload(Replica *r, void *arg __attribute__((unused)))
|
|
|
081b2d |
|
|
|
081b2d |
ruv_force_csn_update_from_ruv(upper_bound_ruv, r_ruv,
|
|
|
081b2d |
"Force update of database RUV (from CL RUV) -> ", SLAPI_LOG_NOTICE);
|
|
|
081b2d |
- replica_set_ruv_dirty(r);
|
|
|
081b2d |
}
|
|
|
081b2d |
|
|
|
081b2d |
} else {
|
|
|
081b2d |
@@ -2778,11 +2770,6 @@ replica_write_ruv(Replica *r)
|
|
|
081b2d |
|
|
|
081b2d |
replica_lock(r->repl_lock);
|
|
|
081b2d |
|
|
|
081b2d |
- if (!r->repl_ruv_dirty) {
|
|
|
081b2d |
- replica_unlock(r->repl_lock);
|
|
|
081b2d |
- return rc;
|
|
|
081b2d |
- }
|
|
|
081b2d |
-
|
|
|
081b2d |
PR_ASSERT(r->repl_ruv);
|
|
|
081b2d |
|
|
|
081b2d |
ruv_to_smod((RUV *)object_get_data(r->repl_ruv), &smod);
|
|
|
081b2d |
@@ -2817,14 +2804,10 @@ replica_write_ruv(Replica *r)
|
|
|
081b2d |
/* ruv does not exist - create one */
|
|
|
081b2d |
replica_lock(r->repl_lock);
|
|
|
081b2d |
|
|
|
081b2d |
- if (rc == LDAP_SUCCESS) {
|
|
|
081b2d |
- r->repl_ruv_dirty = PR_FALSE;
|
|
|
081b2d |
- } else if (rc == LDAP_NO_SUCH_OBJECT) {
|
|
|
081b2d |
+ if (rc == LDAP_NO_SUCH_OBJECT) {
|
|
|
081b2d |
/* this includes an internal operation - but since this only happens
|
|
|
081b2d |
during server startup - its ok that we have lock around it */
|
|
|
081b2d |
rc = _replica_configure_ruv(r, PR_TRUE);
|
|
|
081b2d |
- if (rc == 0)
|
|
|
081b2d |
- r->repl_ruv_dirty = PR_FALSE;
|
|
|
081b2d |
} else /* error */
|
|
|
081b2d |
{
|
|
|
081b2d |
slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
|
|
|
081b2d |
@@ -3325,7 +3308,6 @@ replica_create_ruv_tombstone(Replica *r)
|
|
|
081b2d |
|
|
|
081b2d |
if (ruv_init_new(csnstr, r->repl_rid, purl, &ruv) == RUV_SUCCESS) {
|
|
|
081b2d |
r->repl_ruv = object_new((void *)ruv, (FNFree)ruv_destroy);
|
|
|
081b2d |
- r->repl_ruv_dirty = PR_TRUE;
|
|
|
081b2d |
return_value = LDAP_SUCCESS;
|
|
|
081b2d |
} else {
|
|
|
081b2d |
slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "replica_create_ruv_tombstone - "
|
|
|
081b2d |
@@ -3365,8 +3347,6 @@ replica_create_ruv_tombstone(Replica *r)
|
|
|
081b2d |
slapi_add_internal_pb(pb);
|
|
|
081b2d |
e = NULL; /* add consumes e, upon success or failure */
|
|
|
081b2d |
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value);
|
|
|
081b2d |
- if (return_value == LDAP_SUCCESS)
|
|
|
081b2d |
- r->repl_ruv_dirty = PR_FALSE;
|
|
|
081b2d |
|
|
|
081b2d |
done:
|
|
|
081b2d |
slapi_entry_free(e);
|
|
|
081b2d |
@@ -3630,7 +3610,6 @@ replica_strip_cleaned_rids(Replica *r)
|
|
|
081b2d |
ruv_get_cleaned_rids(ruv, rid);
|
|
|
081b2d |
while (rid[i] != 0) {
|
|
|
081b2d |
ruv_delete_replica(ruv, rid[i]);
|
|
|
081b2d |
- replica_set_ruv_dirty(r);
|
|
|
081b2d |
if (replica_write_ruv(r)) {
|
|
|
081b2d |
slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
|
|
|
081b2d |
"replica_strip_cleaned_rids - Failed to write RUV\n");
|
|
|
081b2d |
@@ -3744,15 +3723,6 @@ replica_update_ruv_consumer(Replica *r, RUV *supplier_ruv)
|
|
|
081b2d |
}
|
|
|
081b2d |
}
|
|
|
081b2d |
|
|
|
081b2d |
-void
|
|
|
081b2d |
-replica_set_ruv_dirty(Replica *r)
|
|
|
081b2d |
-{
|
|
|
081b2d |
- PR_ASSERT(r);
|
|
|
081b2d |
- replica_lock(r->repl_lock);
|
|
|
081b2d |
- r->repl_ruv_dirty = PR_TRUE;
|
|
|
081b2d |
- replica_unlock(r->repl_lock);
|
|
|
081b2d |
-}
|
|
|
081b2d |
-
|
|
|
081b2d |
PRBool
|
|
|
081b2d |
replica_is_state_flag_set(Replica *r, int32_t flag)
|
|
|
081b2d |
{
|
|
|
081b2d |
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
|
|
|
081b2d |
index 9c8d6adbb..e025f34d8 100644
|
|
|
081b2d |
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
|
|
|
081b2d |
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
|
|
|
081b2d |
@@ -937,7 +937,6 @@ replica_config_change_type_and_id(Replica *r, const char *new_type, const char *
|
|
|
081b2d |
replica_reset_csn_pl(r);
|
|
|
081b2d |
}
|
|
|
081b2d |
ruv_delete_replica(ruv, oldrid);
|
|
|
081b2d |
- replica_set_ruv_dirty(r);
|
|
|
081b2d |
cl5CleanRUV(oldrid);
|
|
|
081b2d |
replica_set_csn_assigned(r);
|
|
|
081b2d |
}
|
|
|
081b2d |
@@ -1323,7 +1322,6 @@ replica_execute_cleanruv_task(Object *r, ReplicaId rid, char *returntext __attri
|
|
|
081b2d |
return LDAP_UNWILLING_TO_PERFORM;
|
|
|
081b2d |
}
|
|
|
081b2d |
rc = ruv_delete_replica(local_ruv, rid);
|
|
|
081b2d |
- replica_set_ruv_dirty(replica);
|
|
|
081b2d |
if (replica_write_ruv(replica)) {
|
|
|
081b2d |
slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "cleanAllRUV_task - Could not write RUV\n");
|
|
|
081b2d |
}
|
|
|
081b2d |
--
|
|
|
081b2d |
2.13.6
|
|
|
081b2d |
|