ldap/servers/plugins/replication/cl5_api.c | 17
ldap/servers/plugins/replication/repl5.h | 29
ldap/servers/plugins/replication/repl5_agmt.c | 110 -
ldap/servers/plugins/replication/repl5_agmtlist.c | 12
ldap/servers/plugins/replication/repl5_connection.c | 7
ldap/servers/plugins/replication/repl5_init.c | 70 +
ldap/servers/plugins/replication/repl5_replica.c | 131 --
ldap/servers/plugins/replication/repl5_replica_config.c | 960 +++++++++-------
ldap/servers/plugins/replication/repl_extop.c | 265 +++-
ldap/servers/plugins/replication/replutil.c | 2
ldap/servers/slapd/back-ldbm/ldbm_modify.c | 8
ldap/servers/slapd/back-ldbm/misc.c | 6
ldap/servers/slapd/back-ldbm/proto-back-ldbm.h | 1
ldap/servers/slapd/entry.c | 13
ldap/servers/slapd/slapi-private.h | 1
15 files changed, 1002 insertions(+), 630 deletions(-)
New commits:
commit f9abb940b8c35162618dabde74a62dc37f90102b
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Fri Nov 16 10:59:57 2012 -0500
Ticket 332 - CLEANALLRUV 2.0 Testing
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index f7960db..6d65680 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -1466,13 +1466,13 @@ int cl5WriteOperation(const char *replName, const char *replGen,
}
/* Name: cl5CreateReplayIterator
- Description: creates an iterator that allows to retireve changes that should
- to be sent to the consumer identified by ruv. The iteration is peformed by
+ Description: creates an iterator that allows to retrieve changes that should
+ to be sent to the consumer identified by ruv. The iteration is performed by
repeated calls to cl5GetNextOperationToReplay.
Parameters: replica - replica whose data we wish to iterate;
ruv - consumer ruv;
iterator - iterator to be passed to cl5GetNextOperationToReplay call
- Return: CL5_SUCCESS, if function is successfull;
+ Return: CL5_SUCCESS, if function is successful;
CL5_MISSING_DATA, if data that should be in the changelog is missing
CL5_PURGED_DATA, if some data that consumer needs has been purged.
Note that the iterator can be non null if the supplier contains
@@ -1480,7 +1480,7 @@ int cl5WriteOperation(const char *replName, const char *replGen,
CL5_NOTFOUND if the consumer is up to data with respect to the supplier
CL5_BAD_DATA if invalid parameter is passed;
CL5_BAD_STATE if db has not been open;
- CL5_DB_ERROR if any other db error occured;
+ CL5_DB_ERROR if any other db error occurred;
CL5_MEMORY_ERROR if memory allocation fails.
Algorithm: Build a list of csns from consumer's and supplier's ruv. For each element
of the consumer's ruv put max csn into the csn list. For each element
@@ -1495,7 +1495,7 @@ int cl5WriteOperation(const char *replName, const char *replGen,
we can bring the consumer up to date.
Position the db cursor on the change entry that corresponds to this csn.
Hash entries are created for each replica traversed so far. sendChanges
- flag is set to FALSE for all repolicas except the last traversed.
+ flag is set to FALSE for all replicas except the last traversed.
*/
int cl5CreateReplayIteratorEx (Private_Repl_Protocol *prp, const RUV *consumerRuv,
@@ -6532,6 +6532,8 @@ cl5CleanRUV(ReplicaId rid){
CL5DBFile *file;
Object *obj;
+ slapi_rwlock_wrlock (s_cl5Desc.stLock);
+
obj = objset_first_obj(s_cl5Desc.dbFiles);
while (obj){
file = (CL5DBFile *)object_get_data(obj);
@@ -6539,6 +6541,11 @@ cl5CleanRUV(ReplicaId rid){
ruv_delete_replica(file->maxRUV, rid);
obj = objset_next_obj(s_cl5Desc.dbFiles, obj);
}
+ if (obj) {
+ object_release (obj);
+ }
+
+ slapi_rwlock_unlock (s_cl5Desc.stLock);
}
void trigger_cl_trimming(ReplicaId rid){
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
index 31231ac..dc03333 100644
--- a/ldap/servers/plugins/replication/repl5.h
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -97,8 +97,14 @@
/* cleanallruv extended ops */
#define REPL_CLEANRUV_OID "2.16.840.1.113730.3.6.5"
#define REPL_ABORT_CLEANRUV_OID "2.16.840.1.113730.3.6.6"
-#define CLEANRUV_NOTIFIED 0
-#define CLEANRUV_RELEASED 1
+#define REPL_CLEANRUV_GET_MAXCSN_OID "2.16.840.1.113730.3.6.7"
+#define REPL_CLEANRUV_CHECK_STATUS_OID "2.16.840.1.113730.3.6.8"
+
+#define CLEANRUV_ACCEPTED "accepted"
+#define CLEANRUV_REJECTED "rejected"
+#define CLEANRUV_FINISHED "finished"
+#define CLEANRUV_CLEANING "cleaning"
+#define CLEANRUV_NO_MAXCSN "no maxcsn"
/* DS 5.0 replication protocol error codes */
#define NSDS50_REPL_REPLICA_READY 0x00 /* Replica ready, go ahead */
@@ -227,6 +233,9 @@ int multimaster_extop_StartNSDS50ReplicationRequest(Slapi_PBlock *pb);
int multimaster_extop_EndNSDS50ReplicationRequest(Slapi_PBlock *pb);
int multimaster_extop_cleanruv(Slapi_PBlock *pb);
int multimaster_extop_abort_cleanruv(Slapi_PBlock *pb);
+int multimaster_extop_cleanruv_get_maxcsn(Slapi_PBlock *pb);
+int multimaster_extop_cleanruv_check_status(Slapi_PBlock *pb);
+
int extop_noop(Slapi_PBlock *pb);
struct berval *NSDS50StartReplicationRequest_new(const char *protocol_oid,
const char *repl_root, char **extra_referrals, CSN *csn);
@@ -309,6 +318,7 @@ char *agmt_get_binddn(const Repl_Agmt *ra);
struct berval *agmt_get_credentials(const Repl_Agmt *ra);
int agmt_get_bindmethod(const Repl_Agmt *ra);
Slapi_DN *agmt_get_replarea(const Repl_Agmt *ra);
+Slapi_DN *agmt_get_replarea_by_ref(const Repl_Agmt *ra);
int agmt_is_fractional(const Repl_Agmt *ra);
int agmt_is_fractional_attr(const Repl_Agmt *ra, const char *attrname);
int agmt_is_fractional_attr_total(const Repl_Agmt *ra, const char *attrname);
@@ -357,9 +367,6 @@ void agmt_set_priv (Repl_Agmt *agmt, void* priv);
int get_agmt_agreement_type ( Repl_Agmt *agmt);
void* agmt_get_connection( Repl_Agmt *ra);
int agmt_has_protocol(Repl_Agmt *agmt);
-void agmt_set_cleanruv_notified_from_entry(Repl_Agmt *ra, Slapi_Entry *e);
-int agmt_set_cleanruv_data(Repl_Agmt *ra, ReplicaId rid, int op);
-int agmt_is_cleanruv_notified(Repl_Agmt *ra, ReplicaId rid);
typedef struct replica Replica;
@@ -444,6 +451,7 @@ LDAP * conn_get_ldap(Repl_Connection *conn);
void conn_lock(Repl_Connection *conn);
void conn_unlock(Repl_Connection *conn);
void conn_delete_internal_ext(Repl_Connection *conn);
+const char* conn_get_bindmethod(Repl_Connection *conn);
/* In repl5_protocol.c */
typedef struct repl_protocol Repl_Protocol;
@@ -598,7 +606,7 @@ int replica_config_init();
void replica_config_destroy ();
int get_replica_type(Replica *r);
int replica_execute_cleanruv_task_ext(Object *r, ReplicaId rid);
-void add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn);
+void add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn, char *forcing);
int is_cleaned_rid(ReplicaId rid);
int replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
int *returncode, char *returntext, void *arg);
@@ -606,18 +614,15 @@ void replica_cleanallruv_thread_ext(void *arg);
void stop_ruv_cleaning();
int task_aborted();
void replica_abort_task_thread(void *arg);
-void delete_cleaned_rid(Replica *r, ReplicaId rid, CSN *maxcsn);
+void remove_cleaned_rid(ReplicaId rid);
int process_repl_agmts(Replica *replica, int *agmt_info, char *oid, Slapi_Task *task, struct berval *payload, int op);
int decode_cleanruv_payload(struct berval *extop_value, char **payload);
-struct berval *create_ruv_payload(char *value);
-void replica_add_cleanruv_data(Replica *r, char *val);
-void replica_remove_cleanruv_data(Replica *r, char *val);
-CSN *replica_get_cleanruv_maxcsn(Replica *r, ReplicaId rid);
+struct berval *create_cleanruv_payload(char *value);
void ruv_get_cleaned_rids(RUV *ruv, ReplicaId *rids);
void add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root);
int is_task_aborted(ReplicaId rid);
int is_pre_cleaned_rid(ReplicaId rid);
-void delete_aborted_rid(Replica *replica, ReplicaId rid, char *repl_root);
+void delete_aborted_rid(Replica *replica, ReplicaId rid, char *repl_root, int skip);
void set_cleaned_rid(ReplicaId rid);
void set_aborted_rid(ReplicaId rid);
void cleanruv_log(Slapi_Task *task, char *task_type, char *fmt, ...);
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
index c63524b..8f115d4 100644
--- a/ldap/servers/plugins/replication/repl5_agmt.c
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
@@ -138,7 +138,6 @@ typedef struct repl5agmt {
for sync agreements or for replication session plug-in
private data for normal replication agreements */
int agreement_type;
- int cleanruv_notified[CLEANRIDSIZ + 1]; /* specifies if the replica has been notified of a CLEANALLRUV task */
} repl5agmt;
/* Forward declarations */
@@ -229,7 +228,6 @@ agmt_new_from_entry(Slapi_Entry *e)
Repl_Agmt *ra;
char *tmpstr;
Slapi_Attr *sattr;
- char **clean_vals = NULL;
char **denied_attrs = NULL;
char *auto_initialize = NULL;
@@ -388,20 +386,6 @@ agmt_new_from_entry(Slapi_Entry *e)
ra->last_init_end_time = 0UL;
ra->last_init_start_time = 0UL;
ra->last_init_status[0] = '\0';
-
- /* cleanruv notification */
- clean_vals = slapi_entry_attr_get_charray(e, type_nsds5ReplicaCleanRUVnotified);
- if(clean_vals){
- int i;
- for (i = 0; i < CLEANRIDSIZ && clean_vals[i]; i++){
- ra->cleanruv_notified[i] = atoi(clean_vals[i]);
- }
- if(i < CLEANRIDSIZ)
- ra->cleanruv_notified[i + 1] = 0;
- slapi_ch_array_free(clean_vals);
- } else {
- ra->cleanruv_notified[0] = 0;
- }
/* Fractional attributes */
slapi_entry_attr_find(e, type_nsds5ReplicatedAttributeList, &sattr);
@@ -801,6 +785,17 @@ agmt_get_replarea(const Repl_Agmt *ra)
return return_value;
}
+Slapi_DN *
+agmt_get_replarea_by_ref(const Repl_Agmt *ra)
+{
+ Slapi_DN *return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->replarea;
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
int
agmt_is_fractional(const Repl_Agmt *ra)
{
@@ -2458,86 +2453,3 @@ agmt_has_protocol(Repl_Agmt *agmt)
}
return 0;
}
-
-int
-agmt_is_cleanruv_notified(Repl_Agmt *ra, ReplicaId rid){
- int notified = 0;
- int i;
-
- PR_Lock(ra->lock);
- for(i = 0; i < CLEANRIDSIZ && ra->cleanruv_notified[i]; i++){
- if(ra->cleanruv_notified[i] == rid){
- notified = 1;
- break;
- }
- }
- PR_Unlock(ra->lock);
-
- return notified;
-}
-
-/*
- * This will trigger agmt_set_cleanruv_notified_from_entry() to be called,
- * which will update the in memory agmt.
- *
- * op can be: CLEANRUV_NOTIFIED or CLEANRUV_RELEASED
- */
-int
-agmt_set_cleanruv_data(Repl_Agmt *ra, ReplicaId rid, int op){
- Slapi_PBlock *pb;
- LDAPMod *mods[2];
- LDAPMod mod;
- struct berval *vals[2];
- struct berval val;
- char data[6];
- int rc = 0;
-
- if(ra == NULL){
- return -1;
- }
-
- if(op == CLEANRUV_NOTIFIED){
- /* add the cleanruv data */
- mod.mod_op = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
- } else {
- /* remove the cleanruv data */
- mod.mod_op = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
- }
-
- pb = slapi_pblock_new();
- val.bv_len = PR_snprintf(data, sizeof(data), "%d", (int)rid);
- mod.mod_type = (char *)type_nsds5ReplicaCleanRUVnotified;
- mod.mod_bvalues = vals;
- vals [0] = &val;
- vals [1] = NULL;
- val.bv_val = data;
- mods[0] = &mod;
- mods[1] = NULL;
-
- slapi_modify_internal_set_pb_ext (pb, ra->dn, mods, NULL, NULL,
- repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
- slapi_modify_internal_pb (pb);
- slapi_pblock_destroy(pb);
-
- return rc;
-}
-
-void
-agmt_set_cleanruv_notified_from_entry(Repl_Agmt *ra, Slapi_Entry *e){
- char **attr_vals = NULL;
- int i;
-
- PR_Lock(ra->lock);
- attr_vals = slapi_entry_attr_get_charray(e, type_nsds5ReplicaCleanRUVnotified);
- if(attr_vals){
- for (i = 0; i < CLEANRIDSIZ && attr_vals[i]; i++){
- ra->cleanruv_notified[i] = atoi(attr_vals[i]);
- }
- if( i < CLEANRIDSIZ )
- ra->cleanruv_notified[i + 1] = 0;
- slapi_ch_array_free(attr_vals);
- } else {
- ra->cleanruv_notified[0] = 0;
- }
- PR_Unlock(ra->lock);
-}
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
index 6b5dab4..7041bbc 100644
--- a/ldap/servers/plugins/replication/repl5_agmtlist.c
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
@@ -246,7 +246,11 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
/* we don't allow delete attribute operations unless it was issued by
the replication plugin - handled above */
if (mods[i]->mod_op & LDAP_MOD_DELETE)
- {
+ {
+ if(strcasecmp (mods[i]->mod_type, type_nsds5ReplicaCleanRUVnotified) == 0){
+ /* allow the deletion of cleanallruv agmt attr */
+ continue;
+ }
slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
"deletion of %s attribute is not allowed\n", type_nsds5ReplicaInitialize);
*returncode = LDAP_UNWILLING_TO_PERFORM;
@@ -485,13 +489,9 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
strcasecmp (mods[i]->mod_type, "modifiersname") == 0 ||
strcasecmp (mods[i]->mod_type, "description") == 0)
{
- /* ignore modifier's name and timestamp attributes and the description. */
+ /* ignore last mod attrs, and the description. */
continue;
}
- else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaCleanRUVnotified))
- {
- agmt_set_cleanruv_notified_from_entry(agmt, e);
- }
else if (0 == windows_handle_modify_agreement(agmt, mods[i]->mod_type, e))
{
slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
diff --git a/ldap/servers/plugins/replication/repl5_connection.c b/ldap/servers/plugins/replication/repl5_connection.c
index 51a2bc5..15a5f64 100644
--- a/ldap/servers/plugins/replication/repl5_connection.c
+++ b/ldap/servers/plugins/replication/repl5_connection.c
@@ -263,7 +263,6 @@ conn_delete(Repl_Connection *conn)
}
}
-
/*
* Return the last operation type processed by the connection
* object, and the LDAP error encountered.
@@ -1760,6 +1759,12 @@ bind_method_to_mech(int bindmethod)
return LDAP_SASL_SIMPLE;
}
+const char*
+conn_get_bindmethod(Repl_Connection *conn)
+{
+ return (bind_method_to_mech(conn->bindmethod));
+}
+
/*
* Check the result of an ldap BIND operation to see we it
* contains the expiration controls
diff --git a/ldap/servers/plugins/replication/repl5_init.c b/ldap/servers/plugins/replication/repl5_init.c
index 7a80c6f..498f6c1 100644
--- a/ldap/servers/plugins/replication/repl5_init.c
+++ b/ldap/servers/plugins/replication/repl5_init.c
@@ -123,7 +123,7 @@ static char *cleanruv_oid_list[] = {
NULL
};
static char *cleanruv_name_list[] = {
- NSDS_REPL_NAME_PREFIX " Cleanruv",
+ NSDS_REPL_NAME_PREFIX " CleanAllRUV",
NULL
};
static char *cleanruv_abort_oid_list[] = {
@@ -131,9 +131,26 @@ static char *cleanruv_abort_oid_list[] = {
NULL
};
static char *cleanruv_abort_name_list[] = {
- NSDS_REPL_NAME_PREFIX " Cleanruv Abort",
+ NSDS_REPL_NAME_PREFIX " CleanAllRUV Abort",
NULL
};
+static char *cleanruv_maxcsn_oid_list[] = {
+ REPL_CLEANRUV_GET_MAXCSN_OID,
+ NULL
+};
+static char *cleanruv_maxcsn_name_list[] = {
+ NSDS_REPL_NAME_PREFIX " CleanAllRUV Retrieve MaxCSN",
+ NULL
+};
+static char *cleanruv_status_oid_list[] = {
+ REPL_CLEANRUV_CHECK_STATUS_OID,
+ NULL
+};
+static char *cleanruv_status_name_list[] = {
+ NSDS_REPL_NAME_PREFIX " CleanAllRUV Check Status",
+ NULL
+};
+
/* List of plugin identities for every plugin registered. Plugin identity
is passed by the server in the plugin init function and must be supplied
@@ -496,6 +513,53 @@ multimaster_cleanruv_abort_extop_init( Slapi_PBlock *pb )
return rc;
}
+int
+multimaster_cleanruv_maxcsn_extop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+ void *identity = NULL;
+
+ /* get plugin identity and store it to pass to internal operations */
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
+ PR_ASSERT (identity);
+
+ if (slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterextopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, (void *)cleanruv_maxcsn_oid_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, (void *)cleanruv_maxcsn_name_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)multimaster_extop_cleanruv_get_maxcsn ))
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_cleanruv_extop_init failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+int
+multimaster_cleanruv_status_extop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+ void *identity = NULL;
+
+ /* get plugin identity and store it to pass to internal operations */
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
+ PR_ASSERT (identity);
+
+ if (slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterextopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, (void *)cleanruv_status_oid_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, (void *)cleanruv_status_name_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)multimaster_extop_cleanruv_check_status ))
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_cleanruv_extop_init failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+
static PRBool
check_for_ldif_dump(Slapi_PBlock *pb)
{
@@ -679,6 +743,8 @@ int replication_multimaster_plugin_init(Slapi_PBlock *pb)
rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_response_extop_init", multimaster_response_extop_init, "Multimaster replication extended response plugin", NULL, identity);
rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_cleanruv_extop_init", multimaster_cleanruv_extop_init, "Multimaster replication cleanruv extended operation plugin", NULL, identity);
rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_cleanruv_abort_extop_init", multimaster_cleanruv_abort_extop_init, "Multimaster replication cleanruv abort extended operation plugin", NULL, identity);
+ rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_cleanruv_maxcsn_extop_init", multimaster_cleanruv_maxcsn_extop_init, "Multimaster replication cleanruv maxcsn extended operation plugin", NULL, identity);
+ rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_cleanruv_status_extop_init", multimaster_cleanruv_status_extop_init, "Multimaster replication cleanruv status extended operation plugin", NULL, identity);
if (0 == rc)
{
multimaster_initialised = 1;
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
index ec0b113..de0fa66 100644
--- a/ldap/servers/plugins/replication/repl5_replica.c
+++ b/ldap/servers/plugins/replication/repl5_replica.c
@@ -88,7 +88,6 @@ struct replica {
PRBool state_update_inprogress; /* replica state is being updated */
PRLock *agmt_lock; /* protects agreement creation, start and stop */
char *locking_purl; /* supplier who has exclusive access */
- char *repl_cleanruv_data[CLEANRIDSIZ + 1];
};
@@ -313,7 +312,6 @@ replica_destroy(void **arg)
{
Replica *r;
void *repl_name;
- int i;
if (arg == NULL)
return;
@@ -400,10 +398,6 @@ replica_destroy(void **arg)
csnplFree(&r->min_csn_pl);;
}
- for(i = 0;r->repl_cleanruv_data[i] != NULL; i++){
- slapi_ch_free_string(&r->repl_cleanruv_data[i]);
- }
-
slapi_ch_free((void **)arg);
}
@@ -1830,12 +1824,13 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
PRThread *thread = NULL;
struct berval *payload = NULL;
CSN *maxcsn = NULL;
- char *csnpart;
- char *iter;
+ ReplicaId rid;
char csnstr[CSN_STRSIZE];
- char *ridstr;
+ char *forcing = NULL;
char *token = NULL;
- ReplicaId rid;
+ char *csnpart;
+ char *ridstr;
+ char *iter;
int i;
for(i = 0; i < CLEANRIDSIZ && clean_vals[i]; i++){
@@ -1844,7 +1839,6 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
/*
* Set the cleanruv data, and add the cleaned rid
*/
- r->repl_cleanruv_data[i] = slapi_ch_strdup(clean_vals[i]);
token = ldap_utf8strtok_r(clean_vals[i], ":", &iter);
if(token){
rid = atoi(token);
@@ -1862,16 +1856,18 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
maxcsn = csn_new();
csn_init_by_string(maxcsn, csnpart);
csn_as_string(maxcsn, PR_FALSE, csnstr);
- add_cleaned_rid(rid, r, csnstr);
- set_cleaned_rid(rid);
+ forcing = ldap_utf8strtok_r(iter, ":", &iter);
+ if(forcing == NULL){
+ forcing = "no";
+ }
slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: cleanAllRUV task found, "
"resuming the cleaning of rid(%d)...\n", rid);
/*
* Create payload
*/
- ridstr = slapi_ch_smprintf("%d:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(r)), csnstr);
- payload = create_ruv_payload(ridstr);
+ ridstr = slapi_ch_smprintf("%d:%s:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(r)), csnstr, forcing);
+ payload = create_cleanruv_payload(ridstr);
slapi_ch_free_string(&ridstr);
if(payload == NULL){
@@ -1894,8 +1890,10 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
data->rid = rid;
data->task = NULL;
data->maxcsn = maxcsn;
- data->sdn = slapi_sdn_dup(r->repl_root);
data->payload = payload;
+ data->sdn = slapi_sdn_dup(r->repl_root);
+ data->force = slapi_ch_strdup(forcing);
+ data->repl_root = NULL;
thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread_ext,
(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
@@ -1906,12 +1904,12 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
"thread for rid(%d)\n", (int)data->rid);
csn_free(&maxcsn);
slapi_sdn_free(&data->sdn);
+ slapi_ch_free_string(&data->force);
ber_bvfree(data->payload);
slapi_ch_free((void **)&data);
}
}
}
- r->repl_cleanruv_data[i] = NULL;
done:
slapi_ch_array_free(clean_vals);
@@ -1921,13 +1919,12 @@ done:
{
PRThread *thread = NULL;
struct berval *payload;
- CSN *maxcsn = NULL;
- char *iter;
+ ReplicaId rid;
+ char *certify = NULL;
char *ridstr = NULL;
- char *repl_root;
char *token = NULL;
- char *certify = NULL;
- ReplicaId rid;
+ char *repl_root;
+ char *iter;
int i;
for(i = 0; clean_vals[i]; i++){
@@ -1938,23 +1935,27 @@ done:
rid = atoi(token);
if(rid <= 0 || rid >= READ_ONLY_REPLICA_ID){
slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: invalid replica id(%d) "
- "aborting task.\n", rid);
+ "aborting abort task.\n", rid);
goto done2;
}
} else {
slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: unable to parse cleanallruv "
- "data (%s), aborting task.\n",clean_vals[i]);
+ "data (%s), aborting abort task.\n",clean_vals[i]);
goto done2;
}
repl_root = ldap_utf8strtok_r(iter, ":", &iter);
certify = ldap_utf8strtok_r(iter, ":", &iter);
- stop_ruv_cleaning();
- maxcsn = replica_get_cleanruv_maxcsn(r, rid);
- delete_cleaned_rid(r, rid, maxcsn);
- set_aborted_rid(rid);
- csn_free(&maxcsn);
+ if(!is_cleaned_rid(rid)){
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: replica id(%d) is not "
+ "being cleaned, nothing to abort. Aborting abort task.\n", rid);
+ delete_aborted_rid(r, rid, repl_root, 0);
+ goto done2;
+ }
+
+ add_aborted_rid(rid, r, repl_root);
+ stop_ruv_cleaning();
slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: abort task found, "
"resuming abort of rid(%d).\n", rid);
/*
@@ -1964,8 +1965,8 @@ done:
if (data == NULL) {
slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to allocate cleanruv_data.\n");
} else {
- ridstr = slapi_ch_smprintf("%d:%s", rid, repl_root);
- payload = create_ruv_payload(ridstr);
+ ridstr = slapi_ch_smprintf("%d:%s:%s", rid, repl_root, certify);
+ payload = create_cleanruv_payload(ridstr);
slapi_ch_free_string(&ridstr);
if(payload == NULL){
@@ -3463,7 +3464,7 @@ replica_replace_ruv_tombstone(Replica *r)
if (rc != LDAP_SUCCESS)
{
- if ((rc != LDAP_NO_SUCH_OBJECT) || !replica_is_state_flag_set(r, REPLICA_IN_USE))
+ if ((rc != LDAP_NO_SUCH_OBJECT && rc != LDAP_TYPE_OR_VALUE_EXISTS) || !replica_is_state_flag_set(r, REPLICA_IN_USE))
{
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_replace_ruv_tombstone: "
"failed to update replication update vector for replica %s: LDAP "
@@ -3827,69 +3828,3 @@ replica_get_attr ( Slapi_PBlock *pb, const char* type, void *value )
return rc;
}
-
-void
-replica_add_cleanruv_data(Replica *r, char *val)
-{
- int i;
-
- PR_Lock(r->repl_lock);
-
- for (i = 0; i < CLEANRIDSIZ && r->repl_cleanruv_data[i] != NULL; i++); /* goto the end of the list */
- if( i < CLEANRIDSIZ){
- r->repl_cleanruv_data[i] = slapi_ch_strdup(val); /* append to list */
- r->repl_cleanruv_data[i + 1] = 0;
- }
-
- PR_Unlock(r->repl_lock);
-}
-
-void
-replica_remove_cleanruv_data(Replica *r, char *val)
-{
- int i;
-
- PR_Lock(r->repl_lock);
-
- for(i = 0; i < CLEANRIDSIZ && r->repl_cleanruv_data[i] && strcmp(r->repl_cleanruv_data[i], val) != 0; i++);
- if( i < CLEANRIDSIZ ){
- slapi_ch_free_string(&r->repl_cleanruv_data[i]);
- for(; i < CLEANRIDSIZ; i++){
- /* rewrite entire array */
- r->repl_cleanruv_data[i] = r->repl_cleanruv_data[i + 1];
- }
- }
-
- PR_Unlock(r->repl_lock);
-}
-
-CSN *
-replica_get_cleanruv_maxcsn(Replica *r, ReplicaId rid)
-{
- CSN *newcsn;
- char *csnstr;
- char *token;
- char *iter;
- int repl_rid = 0;
- int i;
-
- PR_Lock(r->repl_lock);
-
- for(i = 0; i < CLEANRIDSIZ && r->repl_cleanruv_data[i]; i++){
- token = ldap_utf8strtok_r(r->repl_cleanruv_data[i], ":", &iter);
- if(token){
- repl_rid = atoi(token);
- }
- csnstr = ldap_utf8strtok_r(iter, ":", &iter);
- if(repl_rid == rid){
- newcsn = csn_new();
- csn_init_by_string(newcsn, csnstr);
- PR_Unlock(r->repl_lock);
- return newcsn;
- }
- }
-
- PR_Unlock(r->repl_lock);
-
- return NULL;
-}
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index fe34f4b..3b354f2 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -87,12 +87,12 @@ static int replica_execute_ldif2cl_task (Object *r, char *returntext);
static int replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext);
static int replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, const char *force_cleaning, char *returntext);
static void replica_cleanallruv_thread(void *arg);
-static void replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task);
+static void replica_send_cleanruv_task(Repl_Agmt *agmt, cleanruv_data *clean_data);
static int check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task);
-static int check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_Task *task);
-static int replica_cleanallruv_send_extop(Repl_Agmt *ra, ReplicaId rid, Slapi_Task *task, struct berval *payload, int check_result);
+static int check_agmts_are_caught_up(Replica *replica, char *basedn, ReplicaId rid, char *maxcsn, Slapi_Task *task);
+static int replica_cleanallruv_send_extop(Repl_Agmt *ra, cleanruv_data *data, int check_result);
static int replica_cleanallruv_send_abort_extop(Repl_Agmt *ra, Slapi_Task *task, struct berval *payload);
-static int replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *rid_text, char *maxcsn, Slapi_Task *task);
+static int replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *basedn, char *rid_text, char *maxcsn, Slapi_Task *task);
static int replica_cleanallruv_replica_alive(Repl_Agmt *agmt);
static int replica_cleanallruv_check_ruv(Repl_Agmt *ra, char *rid_text, Slapi_Task *task);
static int get_cleanruv_task_count();
@@ -100,6 +100,12 @@ static int get_abort_cleanruv_task_count();
static void preset_cleaned_rid(ReplicaId rid);
static int replica_cleanup_task (Object *r, const char *task_name, char *returntext, int apply_mods);
static int replica_task_done(Replica *replica);
+static void delete_cleaned_rid_config(cleanruv_data *data);
+static int replica_cleanallruv_is_finished(Repl_Agmt *agmt, char *filter, Slapi_Task *task);
+static void check_replicas_are_done_cleaning(cleanruv_data *data);
+static void check_replicas_are_done_aborting(cleanruv_data *data );
+static CSN* replica_cleanallruv_find_maxcsn(Replica *replica, ReplicaId rid, char *basedn);
+static int replica_cleanallruv_get_replica_maxcsn(Repl_Agmt *agmt, char *rid_text, char *basedn, CSN **csn);
static multimaster_mtnode_extension * _replica_config_get_mtnode_ext (const Slapi_Entry *e);
/*
@@ -387,6 +393,12 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
if (apply_mods)
replica_set_legacy_consumer (r, PR_FALSE);
}
+ else if (strcasecmp (config_attr, type_replicaCleanRUV) == 0 ||
+ strcasecmp (config_attr, type_replicaAbortCleanRUV) == 0)
+ {
+ /* only allow the deletion of the cleanAllRUV config attributes */
+ continue;
+ }
else
{
*returncode = LDAP_UNWILLING_TO_PERFORM;
@@ -1230,11 +1242,11 @@ replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
Slapi_Task *task = NULL;
const Slapi_DN *task_dn;
Slapi_DN *dn = NULL;
+ ReplicaId rid;
Object *r;
+ const char *force_cleaning;
const char *base_dn;
const char *rid_str;
- const char *force_cleaning;
- ReplicaId rid;
int rc = SLAPI_DSE_CALLBACK_OK;
/* allocate new task now */
@@ -1245,16 +1257,19 @@ replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
rc = SLAPI_DSE_CALLBACK_ERROR;
goto out;
}
-
/*
* Get our task settings
*/
if ((base_dn = fetch_attr(e, "replica-base-dn", 0)) == NULL){
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Missing replica-base-dn attribute");
+ cleanruv_log(task, CLEANALLRUV_ID, "%s", returntext);
*returncode = LDAP_OBJECT_CLASS_VIOLATION;
rc = SLAPI_DSE_CALLBACK_ERROR;
goto out;
}
if ((rid_str = fetch_attr(e, "replica-id", 0)) == NULL){
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Missing replica-id attribute");
+ cleanruv_log(task, CLEANALLRUV_ID, "%s", returntext);
*returncode = LDAP_OBJECT_CLASS_VIOLATION;
rc = SLAPI_DSE_CALLBACK_ERROR;
goto out;
@@ -1272,8 +1287,6 @@ replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
} else {
force_cleaning = "no";
}
-
-
/*
* Check the rid
*/
@@ -1332,32 +1345,32 @@ out:
static int
replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, const char* force_cleaning, char *returntext)
{
- PRThread *thread = NULL;
+ struct berval *payload = NULL;
Slapi_Task *pre_task = NULL; /* this is supposed to be null for logging */
- Replica *replica;
- Object *ruv_obj;
+ PRThread *thread = NULL;
cleanruv_data *data = NULL;
+ Replica *replica;
CSN *maxcsn = NULL;
- const RUV *ruv;
- struct berval *payload = NULL;
- char *ridstr = NULL;
char csnstr[CSN_STRSIZE];
+ char *ridstr = NULL;
+ char *basedn = NULL;
int rc = 0;
+ cleanruv_log(pre_task, CLEANALLRUV_ID, "Initiating CleanAllRUV Task...");
+
if(get_cleanruv_task_count() >= CLEANRIDSIZ){
/* we are already running the maximum number of tasks */
cleanruv_log(pre_task, CLEANALLRUV_ID,
"Exceeded maximum number of active CLEANALLRUV tasks(%d)",CLEANRIDSIZ);
return LDAP_UNWILLING_TO_PERFORM;
}
-
/*
* Grab the replica
*/
if(r){
replica = (Replica*)object_get_data (r);
} else {
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: replica is NULL, aborting task\n");
+ cleanruv_log(pre_task, CLEANALLRUV_ID, "Replica object is NULL, aborting task");
return -1;
}
/*
@@ -1365,7 +1378,7 @@ replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, c
*/
if(replica_get_type(replica) == REPLICA_TYPE_READONLY){
/* this is a consumer, send error */
- cleanruv_log(pre_task, CLEANALLRUV_ID, "Failed to clean rid (%d), task can not be run on a consumer",rid);
+ cleanruv_log(pre_task, CLEANALLRUV_ID, "Failed to clean rid (%d), task can not be run on a read-only consumer",rid);
if(task){
rc = -1;
slapi_task_finish(task, rc);
@@ -1375,32 +1388,26 @@ replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, c
/*
* Grab the max csn of the deleted replica
*/
- ruv_obj = replica_get_ruv(replica);
- ruv = object_get_data (ruv_obj);
- if(ruv_get_rid_max_csn(ruv, &maxcsn, rid) == RUV_BAD_DATA){
- /* no maxcsn, can not proceed */
- cleanruv_log(pre_task, CLEANALLRUV_ID, "Could not find maxcsn for rid (%d)", rid);
- rc = -1;
- object_release(ruv_obj);
- goto fail;
- } else {
- object_release(ruv_obj);
- if(maxcsn == NULL || csn_get_replicaid(maxcsn) == 0){
- /*
- * This is for consistency with extop csn creation, where
- * we want the csn string to be "0000000000000000000" not ""
- */
- csn_free(&maxcsn);
- maxcsn = csn_new();
- csn_init_by_string(maxcsn, "");
- }
- csn_as_string(maxcsn, PR_FALSE, csnstr);
+ basedn = (char *)slapi_sdn_get_dn(replica_get_root(replica));
+ maxcsn = replica_cleanallruv_find_maxcsn(replica, rid, basedn);
+ if(maxcsn == NULL || csn_get_replicaid(maxcsn) == 0){
+ /*
+ * This is for consistency with extop csn creation, where
+ * we want the csn string to be "0000000000000000000" not ""
+ */
+ csn_free(&maxcsn);
+ maxcsn = csn_new();
+ csn_init_by_string(maxcsn, "");
}
+ csn_as_string(maxcsn, PR_FALSE, csnstr);
+
/*
* Create payload
*/
- ridstr = slapi_ch_smprintf("%d:%s:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(replica)), csnstr, force_cleaning);
- payload = create_ruv_payload(ridstr);
+
+ ridstr = slapi_ch_smprintf("%d:%s:%s:%s", rid, basedn, csnstr, force_cleaning);
+ payload = create_cleanruv_payload(ridstr);
+ cleanruv_log(pre_task, CLEANALLRUV_ID, "Creating payload for (%s)",ridstr); /* MARK */
slapi_ch_free_string(&ridstr);
if(payload == NULL){
@@ -1422,9 +1429,10 @@ replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, c
data->replica = replica;
data->rid = rid;
data->task = task;
- data->maxcsn = maxcsn;
data->payload = payload;
data->sdn = NULL;
+ data->maxcsn = maxcsn;
+ data->repl_root = slapi_ch_strdup(basedn);
data->force = slapi_ch_strdup(force_cleaning);
thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread,
@@ -1433,6 +1441,8 @@ replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, c
if (thread == NULL) {
rc = -1;
slapi_ch_free_string(&data->force);
+ slapi_ch_free_string(&data->repl_root);
+ csn_free(&maxcsn);
goto fail;
} else {
goto done;
@@ -1476,19 +1486,19 @@ replica_cleanallruv_thread_ext(void *arg)
static void
replica_cleanallruv_thread(void *arg)
{
- Object *ruv_obj = NULL;
+ cleanruv_data *data = arg;
Object *agmt_obj = NULL;
+ Object *ruv_obj = NULL;
Repl_Agmt *agmt = NULL;
RUV *ruv = NULL;
- cleanruv_data *data = arg;
char csnstr[CSN_STRSIZE];
char *returntext = NULL;
char *rid_text = NULL;
- int found_dirty_rid = 1;
int agmt_not_notified = 1;
+ int found_dirty_rid = 1;
int interval = 10;
- int aborted = 0;
int free_obj = 0;
+ int aborted = 0;
int rc = 0;
/*
@@ -1501,7 +1511,7 @@ replica_cleanallruv_thread(void *arg)
* the backends might not be online yet.
*/
PR_Lock( notify_lock );
- PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(5) );
+ PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(10) );
PR_Unlock( notify_lock );
data->repl_obj = replica_get_replica_from_dn(data->sdn);
if(data->repl_obj == NULL){
@@ -1523,18 +1533,26 @@ replica_cleanallruv_thread(void *arg)
aborted = 1;
goto done;
}
+ if(data->repl_root == NULL){
+ /* we must have resumed from start up, fill in the repl root */
+ data->repl_root = slapi_ch_strdup(slapi_sdn_get_dn(replica_get_root(data->replica)));
+ }
if(data->task){
slapi_task_begin(data->task, 1);
}
- rid_text = slapi_ch_smprintf("{replica %d ldap", data->rid);
+ /*
+ * Presetting the rid prevents duplicate thread creation, but allows the db and changelog to still
+ * process updates from the rid. set_cleaned_rid() blocks updates, so we don't want to do that... yet.
+ */
+ preset_cleaned_rid(data->rid);
+ rid_text = slapi_ch_smprintf("%d", data->rid);
csn_as_string(data->maxcsn, PR_FALSE, csnstr);
- preset_cleaned_rid(data->rid); /* this prevents duplicate thread creation */
+ add_cleaned_rid(data->rid, data->replica, csnstr, data->force); /* marks config that we started cleaning a rid */
/*
* Add the cleanallruv task to the repl config - so we can handle restarts
*/
cleanruv_log(data->task, CLEANALLRUV_ID, "Cleaning rid (%d)...", data->rid);
- add_cleaned_rid(data->rid, data->replica, csnstr); /* marks config that we started cleaning a rid */
/*
* First, wait for the maxcsn to be covered
*/
@@ -1566,7 +1584,8 @@ replica_cleanallruv_thread(void *arg)
* Make sure all the replicas have seen the max csn
*/
cleanruv_log(data->task, CLEANALLRUV_ID,"Waiting for all the replicas to receive all the deleted replica updates...");
- if(strcasecmp(data->force,"no") == 0 && check_agmts_are_caught_up(data->replica, data->rid, csnstr, data->task)){
+
+ if(strcasecmp(data->force,"no") == 0 && check_agmts_are_caught_up(data->replica, data->repl_root, data->rid, csnstr, data->task)){
/* error, aborted or shutdown */
aborted = 1;
goto done;
@@ -1593,7 +1612,7 @@ replica_cleanallruv_thread(void *arg)
agmt_not_notified = 0;
continue;
}
- if(replica_cleanallruv_send_extop(agmt, data->rid, data->task, data->payload, 1) == 0){
+ if(replica_cleanallruv_send_extop(agmt, data, 1) == 0){
agmt_not_notified = 0;
} else {
agmt_not_notified = 1;
@@ -1663,7 +1682,7 @@ replica_cleanallruv_thread(void *arg)
goto done;
}
if(found_dirty_rid == 0){
- break;
+ break;
}
/*
* need to sleep between passes
@@ -1687,9 +1706,11 @@ done:
*/
if(!aborted){
trigger_cl_trimming(data->rid);
- delete_cleaned_rid(data->replica, data->rid, data->maxcsn);
+ delete_cleaned_rid_config(data);
+ /* make sure all the replicas have been "pre_cleaned" before finishing */
+ check_replicas_are_done_cleaning(data);
cleanruv_log(data->task, CLEANALLRUV_ID, "Successfully cleaned rid(%d).", data->rid);
- slapi_task_finish(data->task, rc);
+ remove_cleaned_rid(data->rid);
} else {
/*
* Shutdown or abort
@@ -1698,10 +1719,12 @@ done:
cleanruv_log(data->task, CLEANALLRUV_ID,"Server shutting down. Process will resume at server startup");
} else {
cleanruv_log(data->task, CLEANALLRUV_ID,"Task aborted for rid(%d).",data->rid);
+ delete_cleaned_rid_config(data);
+ remove_cleaned_rid(data->rid);
}
- if(data->task){
- slapi_task_finish(data->task, rc);
- }
+ }
+ if(data->task){
+ slapi_task_finish(data->task, rc);
}
if(data->payload){
@@ -1710,18 +1733,177 @@ done:
if(data->repl_obj && free_obj){
object_release(data->repl_obj);
}
- slapi_sdn_free(&data->sdn);
+
+ slapi_ch_free_string(&data->repl_root);
slapi_ch_free_string(&data->force);
slapi_ch_free_string(&rid_text);
+ slapi_sdn_free(&data->sdn);
csn_free(&data->maxcsn);
slapi_ch_free((void **)&data);
}
/*
- * Waits for all the repl agmts to be have have the maxcsn. Returns error only on abort or shutdown
+ * Loop over the agmts, and check if they are in the last phase of cleaning, meaning they have
+ * released cleanallruv data from the config
+ */
+static void
+check_replicas_are_done_cleaning(cleanruv_data *data )
+{
+ Object *agmt_obj;
+ Repl_Agmt *agmt;
+ char csnstr[CSN_STRSIZE];
+ char *filter = NULL;
+ int not_all_cleaned = 1;
+ int interval = 10;
+
+ cleanruv_log(data->task, CLEANALLRUV_ID, "Waiting for all the replicas to finish cleaning...");
+
+ csn_as_string(data->maxcsn, PR_FALSE, csnstr);
+ filter = PR_smprintf("(%s=%d:%s:%s)", type_replicaCleanRUV,(int)data->rid, csnstr, data->force);
+
+ while(not_all_cleaned && !is_task_aborted(data->rid) && !slapi_is_shutting_down()){
+ agmt_obj = agmtlist_get_first_agreement_for_replica (data->replica);
+ if(agmt_obj == NULL){
+ not_all_cleaned = 0;
+ break;
+ }
+ while (agmt_obj && !slapi_is_shutting_down()){
+ agmt = (Repl_Agmt*)object_get_data (agmt_obj);
+ if(get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
+ agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
+ not_all_cleaned = 0;
+ continue;
+ }
+ if(replica_cleanallruv_is_finished(agmt, filter, data->task) == 0){
+ not_all_cleaned = 0;
+ } else {
+ not_all_cleaned = 1;
+ break;
+ }
+ agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
+ }
+ if(not_all_cleaned == 0 || is_task_aborted(data->rid) ){
+ break;
+ }
+ cleanruv_log(data->task, CLEANALLRUV_ID, "Not all replicas finished cleaning, retrying in %d seconds",interval);
+ PR_Lock( notify_lock );
+ PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+ PR_Unlock( notify_lock );
+ if(interval < 14400){ /* 4 hour max */
+ interval = interval * 2;
+ } else {
+ interval = 14400;
+ }
+ }
+ slapi_ch_free_string(&filter);
+}
+
+/*
+ * Search this replica for the nsds5ReplicaCleanruv attribute, we don't return
+ * an entry, we know it has finished cleaning.
+ */
+static int
+replica_cleanallruv_is_finished(Repl_Agmt *agmt, char *filter, Slapi_Task *task)
+{
+ Repl_Connection *conn = NULL;
+ ConnResult crc = 0;
+ struct berval *payload = NULL;
+ int msgid = 0;
+ int rc = -1;
+
+ if((conn = conn_new(agmt)) == NULL){
+ return -1;
+ }
+ if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
+ payload = create_cleanruv_payload(filter);
+ crc = conn_send_extended_operation(conn, REPL_CLEANRUV_CHECK_STATUS_OID, payload, NULL, &msgid);
+ if(crc == CONN_OPERATION_SUCCESS){
+ struct berval *retsdata = NULL;
+ char *retoid = NULL;
+
+ crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
+ if (CONN_OPERATION_SUCCESS == crc ){
+ char *response = NULL;
+
+ decode_cleanruv_payload(retsdata, &response);
+ if(response && strcmp(response,CLEANRUV_FINISHED) == 0){
+ /* finished cleaning */
+ rc = 0;
+ }
+ if (NULL != retsdata)
+ ber_bvfree(retsdata);
+ slapi_ch_free_string(&response);
+ slapi_ch_free_string(&retoid);
+ }
+ }
+ } else {
+ rc = -1;
+ }
+ conn_delete_internal_ext(conn);
+ if (NULL != payload)
+ ber_bvfree(payload);
+
+ return rc;
+}
+
+/*
+ * Loop over the agmts, and check if they are in the last phase of aborting, meaning they have
+ * released the abort cleanallruv data from the config
+ */
+static void
+check_replicas_are_done_aborting(cleanruv_data *data )
+{
+ Object *agmt_obj;
+ Repl_Agmt *agmt;
+ char *filter = NULL;
+ int not_all_aborted = 1;
+ int interval = 10;
+
+ cleanruv_log(data->task, ABORT_CLEANALLRUV_ID,"Waiting for all the replicas to finish aborting...");
+
+ filter = PR_smprintf("(%s=%d:%s)", type_replicaAbortCleanRUV, data->rid, data->repl_root);
+ while(not_all_aborted && !slapi_is_shutting_down()){
+ agmt_obj = agmtlist_get_first_agreement_for_replica (data->replica);
+ if(agmt_obj == NULL){
+ not_all_aborted = 0;
+ break;
+ }
+ while (agmt_obj && !slapi_is_shutting_down()){
+ agmt = (Repl_Agmt*)object_get_data (agmt_obj);
+ if(get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
+ agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
+ not_all_aborted = 0;
+ continue;
+ }
+ if(replica_cleanallruv_is_finished(agmt, filter, data->task) == 0){
+ not_all_aborted = 0;
+ } else {
+ not_all_aborted = 1;
+ break;
+ }
+ agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
+ }
+ if(not_all_aborted == 0){
+ break;
+ }
+ cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Not all replicas finished aborting, retrying in %d seconds",interval);
+ PR_Lock( notify_lock );
+ PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+ PR_Unlock( notify_lock );
+ if(interval < 14400){ /* 4 hour max */
+ interval = interval * 2;
+ } else {
+ interval = 14400;
+ }
+ }
+ slapi_ch_free_string(&filter);
+}
+
+/*
+ * Waits for all the repl agmts to be have received the maxcsn. Returns error only on abort or shutdown
*/
static int
-check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_Task *task)
+check_agmts_are_caught_up(Replica *replica, char *basedn, ReplicaId rid, char *maxcsn, Slapi_Task *task)
{
Object *agmt_obj;
Repl_Agmt *agmt;
@@ -1729,7 +1911,7 @@ check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_T
int not_all_caughtup = 1;
int interval = 10;
- rid_text = slapi_ch_smprintf("{replica %d ldap", rid);
+ rid_text = slapi_ch_smprintf("%d", rid);
while(not_all_caughtup && !is_task_aborted(rid) && !slapi_is_shutting_down()){
agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
@@ -1744,7 +1926,7 @@ check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_T
not_all_caughtup = 0;
continue;
}
- if(replica_cleanallruv_check_maxcsn(agmt, rid_text, maxcsn, task) == 0){
+ if(replica_cleanallruv_check_maxcsn(agmt, basedn, rid_text, maxcsn, task) == 0){
not_all_caughtup = 0;
} else {
not_all_caughtup = 1;
@@ -1752,8 +1934,7 @@ check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_T
break;
}
agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
- } /* agmt while */
-
+ }
if(not_all_caughtup == 0 || is_task_aborted(rid) ){
break;
}
@@ -1836,7 +2017,7 @@ check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task)
* Create the CLEANALLRUV extended op payload
*/
struct berval *
-create_ruv_payload(char *value)
+create_cleanruv_payload(char *value)
{
struct berval *req_data = NULL;
BerElement *tmp_bere = NULL;
@@ -1844,10 +2025,7 @@ create_ruv_payload(char *value)
if ((tmp_bere = der_alloc()) == NULL){
goto error;
}
- if (ber_printf(tmp_bere, "{s", value) == -1){
- goto error;
- }
- if (ber_printf(tmp_bere, "}") == -1){
+ if (ber_printf(tmp_bere, "{s}", value) == -1){
goto error;
}
if (ber_flatten(tmp_bere, &req_data) == -1){
@@ -1875,12 +2053,12 @@ done:
* the CLEANALLRUV task.
*/
static void
-replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
+replica_send_cleanruv_task(Repl_Agmt *agmt, cleanruv_data *clean_data)
{
Repl_Connection *conn;
ConnResult crc = 0;
- LDAP *ld;
Slapi_DN *sdn;
+ LDAP *ld;
struct berval *vals[2];
struct berval val;
LDAPMod *mods[2];
@@ -1902,7 +2080,8 @@ replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
conn_delete_internal_ext(conn);
return;
}
- val.bv_len = PR_snprintf(data, sizeof(data), "CLEANRUV%d", rid);
+
+ val.bv_len = PR_snprintf(data, sizeof(data), "CLEANRUV%d", clean_data->rid);
sdn = agmt_get_replarea(agmt);
mod.mod_op = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
mod.mod_type = "nsds5task";
@@ -1919,7 +2098,7 @@ replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
rc = ldap_modify_ext_s( ld, repl_dn, mods, NULL, NULL);
if(rc != LDAP_SUCCESS){
- cleanruv_log(task, CLEANALLRUV_ID, "Failed to add CLEANRUV task replica "
+ cleanruv_log(clean_data->task, CLEANALLRUV_ID, "Failed to add CLEANRUV task replica "
"(%s). You will need to manually run the CLEANRUV task on this replica (%s) error (%d)",
agmt_get_long_name(agmt), agmt_get_hostname(agmt), rc);
}
@@ -2041,7 +2220,7 @@ set_aborted_rid(ReplicaId rid)
* Add the rid and maxcsn to the repl config (so we can resume after a server restart)
*/
void
-add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn)
+add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn, char *forcing)
{
Slapi_PBlock *pb;
struct berval *vals[2];
@@ -2058,7 +2237,7 @@ add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn)
/*
* Write the rid & maxcsn to the config entry
*/
- val.bv_len = PR_snprintf(data, sizeof(data),"%d:%s", rid, maxcsn);
+ val.bv_len = PR_snprintf(data, sizeof(data),"%d:%s:%s", rid, maxcsn, forcing);
dn = replica_get_dn(r);
pb = slapi_pblock_new();
mod.mod_op = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
@@ -2070,13 +2249,11 @@ add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn)
mods[0] = &mod;
mods[1] = NULL;
- replica_add_cleanruv_data(r, val.bv_val);
-
slapi_modify_internal_set_pb (pb, dn, mods, NULL, NULL,
repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
slapi_modify_internal_pb (pb);
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
- if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS){
+ if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS && rc != LDAP_NO_SUCH_OBJECT){
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to update replica "
"config (%d), rid (%d)\n", rc, rid);
}
@@ -2109,6 +2286,7 @@ add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root)
}
}
slapi_rwlock_unlock(abort_rid_lock);
+
/*
* Write the rid to the config entry
*/
@@ -2129,7 +2307,7 @@ add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root)
repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
slapi_modify_internal_pb (pb);
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
- if (rc != LDAP_SUCCESS){
+ if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS && rc != LDAP_NO_SUCH_OBJECT){
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to update "
"replica config (%d), rid (%d)\n", rc, rid);
}
@@ -2140,7 +2318,7 @@ add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root)
}
void
-delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root){
+delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root, int skip){
Slapi_PBlock *pb;
LDAPMod *mods[2];
LDAPMod mod;
@@ -2154,70 +2332,108 @@ delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root){
if(r == NULL)
return;
- /*
- * Remove this rid, and optimize the array
- */
- slapi_rwlock_wrlock(abort_rid_lock);
- for(i = 0; i < CLEANRIDSIZ && aborted_rids[i] != rid; i++); /* found rid, stop */
- for(; i < CLEANRIDSIZ; i++){
- /* rewrite entire array */
- aborted_rids[i] = aborted_rids[i + 1];
+ if(skip){
+ /* skip the deleting of the config, and just remove the in memory rid */
+ slapi_rwlock_wrlock(abort_rid_lock);
+ for(i = 0; i < CLEANRIDSIZ && aborted_rids[i] != rid; i++); /* found rid, stop */
+ for(; i < CLEANRIDSIZ; i++){
+ /* rewrite entire array */
+ aborted_rids[i] = aborted_rids[i + 1];
+ }
+ slapi_rwlock_unlock(abort_rid_lock);
+ } else {
+ /* only remove the config, leave the in-memory rid */
+ dn = replica_get_dn(r);
+ pb = slapi_pblock_new();
+ data = PR_smprintf("%d:%s", (int)rid, repl_root);
+
+ mod.mod_op = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
+ mod.mod_type = (char *)type_replicaAbortCleanRUV;
+ mod.mod_bvalues = vals;
+ vals [0] = &val;
+ vals [1] = NULL;
+ val.bv_val = data;
+ val.bv_len = strlen (data);
+ mods[0] = &mod;
+ mods[1] = NULL;
+
+ slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_modify_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT){
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to remove replica "
+ "config (%d), rid (%d)\n", rc, rid);
+ }
+ slapi_pblock_destroy (pb);
+ slapi_ch_free_string(&dn);
+ slapi_ch_free_string(&data);
}
- slapi_rwlock_unlock(abort_rid_lock);
+}
+
+/*
+ * Just remove the dse.ldif config, but we need to keep the cleaned rids in memory until we know we are done
+ */
+static void
+delete_cleaned_rid_config(cleanruv_data *clean_data)
+{
+ Slapi_PBlock *pb;
+ LDAPMod *mods[2];
+ LDAPMod mod;
+ struct berval *vals[2];
+ struct berval val;
+ char data[CSN_STRSIZE + 15];
+ char csnstr[CSN_STRSIZE];
+ char *dn;
+ int rc;
+
/*
* Prepare the mods for the config entry
*/
- dn = replica_get_dn(r);
+ csn_as_string(clean_data->maxcsn, PR_FALSE, csnstr);
+ val.bv_len = PR_snprintf(data, sizeof(data), "%d:%s:%s", (int)clean_data->rid, csnstr, clean_data->force);
+ dn = replica_get_dn(clean_data->replica);
pb = slapi_pblock_new();
- data = PR_smprintf("%d:%s", (int)rid, repl_root);
-
mod.mod_op = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
- mod.mod_type = (char *)type_replicaAbortCleanRUV;
+ mod.mod_type = (char *)type_replicaCleanRUV;
mod.mod_bvalues = vals;
vals [0] = &val;
vals [1] = NULL;
val.bv_val = data;
- val.bv_len = strlen (data);
mods[0] = &mod;
mods[1] = NULL;
-
slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
slapi_modify_internal_pb (pb);
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
if (rc != LDAP_SUCCESS){
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to remove replica "
- "config (%d), rid (%d)\n", rc, rid);
+ /*
+ * When aborting a task, we don't know if the "force" option was used.
+ * So we assume it is set to "no", but if this op fails, we'll try "yes"
+ */
+ slapi_pblock_destroy (pb);
+ pb = slapi_pblock_new();
+ memset(data,'0',sizeof(data));
+ val.bv_len = PR_snprintf(data, sizeof(data), "%d:%s:yes", (int)clean_data->rid, csnstr);
+ slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_modify_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT){
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to remove replica config "
+ "(%d), rid (%d)\n", rc, clean_data->rid);
+ }
}
slapi_pblock_destroy (pb);
slapi_ch_free_string(&dn);
- slapi_ch_free_string(&data);
}
+
/*
* Remove the rid from our list, and the config
*/
void
-delete_cleaned_rid(Replica *r, ReplicaId rid, CSN *maxcsn)
+remove_cleaned_rid(ReplicaId rid)
{
- Slapi_PBlock *pb;
- Object *agmt_obj;
- Repl_Agmt *agmt;
- LDAPMod *mods[2];
- LDAPMod mod;
- struct berval *vals[2];
- struct berval val;
- char *dn;
- char data[CSN_STRSIZE + 10];
- char csnstr[CSN_STRSIZE];
- int rc;
int i;
- if(r == NULL || maxcsn == NULL)
- return;
-
- /*
- * Remove this rid, and optimize the array
- */
slapi_rwlock_wrlock(rid_lock);
/* do the cleaned rids */
for(i = 0; i < CLEANRIDSIZ && cleaned_rids[i] != rid; i++); /* found rid, stop */
@@ -2232,46 +2448,6 @@ delete_cleaned_rid(Replica *r, ReplicaId rid, CSN *maxcsn)
pre_cleaned_rids[i] = pre_cleaned_rids[i + 1];
}
slapi_rwlock_unlock(rid_lock);
- /*
- * Prepare the mods for the config entry
- */
- csn_as_string(maxcsn, PR_FALSE, csnstr);
- val.bv_len = PR_snprintf(data, sizeof(data), "%d:%s", (int)rid, csnstr);
- dn = replica_get_dn(r);
- pb = slapi_pblock_new();
- mod.mod_op = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
- mod.mod_type = (char *)type_replicaCleanRUV;
- mod.mod_bvalues = vals;
- vals [0] = &val;
- vals [1] = NULL;
- val.bv_val = data;
- mods[0] = &mod;
- mods[1] = NULL;
-
- replica_remove_cleanruv_data(r, data);
-
- slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
- slapi_modify_internal_pb (pb);
- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
- if (rc != LDAP_SUCCESS){
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to remove replica config "
- "(%d), rid (%d)\n", rc, rid);
- }
- slapi_pblock_destroy (pb);
- slapi_ch_free_string(&dn);
- /*
- * Now release the cleaned rid from the repl agmts
- */
- agmt_obj = agmtlist_get_first_agreement_for_replica (r);
- while (agmt_obj){
- agmt = (Repl_Agmt*)object_get_data (agmt_obj);
- if(get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
- agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
- continue;
- }
- agmt_set_cleanruv_data(agmt, rid, CLEANRUV_RELEASED);
- agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
- }
}
/*
@@ -2281,18 +2457,17 @@ int
replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
int *returncode, char *returntext, void *arg)
{
- PRThread *thread = NULL;
struct berval *payload = NULL;
+ cleanruv_data *data = NULL;
+ PRThread *thread = NULL;
Slapi_Task *task = NULL;
+ Slapi_DN *sdn = NULL;
Replica *replica;
ReplicaId rid;
- cleanruv_data *data = NULL;
- Slapi_DN *sdn = NULL;
Object *r;
- CSN *maxcsn = NULL;
+ const char *certify_all;
const char *base_dn;
const char *rid_str;
- const char *certify_all;
char *ridstr = NULL;
int rc = SLAPI_DSE_CALLBACK_OK;
@@ -2316,13 +2491,6 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
rc = SLAPI_DSE_CALLBACK_ERROR;
goto out;
}
- if ((base_dn = fetch_attr(e, "replica-base-dn", 0)) == NULL){
- PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Missing required attr \"replica-base-dn\"");
- cleanruv_log(task, ABORT_CLEANALLRUV_ID, "%s", returntext);
- *returncode = LDAP_OBJECT_CLASS_VIOLATION;
- rc = SLAPI_DSE_CALLBACK_ERROR;
- goto out;
- }
certify_all = fetch_attr(e, "replica-certify-all", 0);
/*
* Check the rid
@@ -2336,9 +2504,33 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
rc = SLAPI_DSE_CALLBACK_ERROR;
goto out;
}
- if(is_aborted_rid(rid)){
+ if(is_task_aborted(rid)){
/* we are already cleaning this rid */
- PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Replica id (%d) is already being aborted", rid);
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Replica id (%d) is already being aborted", rid);
+ cleanruv_log(task, ABORT_CLEANALLRUV_ID, "%s", returntext);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ if ((base_dn = fetch_attr(e, "replica-base-dn", 0)) == NULL){
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Missing required attr \"replica-base-dn\"");
+ cleanruv_log(task, ABORT_CLEANALLRUV_ID, "%s", returntext);
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ if(!is_cleaned_rid(rid) && !is_pre_cleaned_rid(rid)){
+ /* we are already aborting this rid */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Replica id (%d) is not being cleaned, nothing to abort.", rid);
+ cleanruv_log(task, ABORT_CLEANALLRUV_ID, "%s", returntext);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ if(is_task_aborted(rid)){
+ /* we are already aborting this rid */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Replica id (%d) is already being aborted", rid);
cleanruv_log(task, ABORT_CLEANALLRUV_ID, "%s", returntext);
*returncode = LDAP_UNWILLING_TO_PERFORM;
rc = SLAPI_DSE_CALLBACK_ERROR;
@@ -2368,13 +2560,13 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
goto out;
}
} else {
- certify_all = "no";
+ certify_all = "yes";
}
/*
* Create payload
*/
ridstr = slapi_ch_smprintf("%d:%s:%s", rid, base_dn, certify_all);
- payload = create_ruv_payload(ridstr);
+ payload = create_cleanruv_payload(ridstr);
if(payload == NULL){
cleanruv_log(task, ABORT_CLEANALLRUV_ID, "Failed to create extended op payload, aborting task");
@@ -2386,8 +2578,6 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
* Stop the cleaning, and delete the rid
*/
replica = (Replica*)object_get_data (r);
- maxcsn = replica_get_cleanruv_maxcsn(replica, rid);
- delete_cleaned_rid(replica, rid, maxcsn);
add_aborted_rid(rid, replica, (char *)base_dn);
stop_ruv_cleaning();
/*
@@ -2415,12 +2605,12 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
if (thread == NULL) {
object_release(r);
cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Unable to create abort thread. Aborting task.");
+ slapi_ch_free_string(&data->certify);
*returncode = LDAP_OPERATIONS_ERROR;
rc = SLAPI_DSE_CALLBACK_ERROR;
}
out:
- csn_free(&maxcsn);
slapi_ch_free_string(&ridstr);
slapi_sdn_free(&sdn);
@@ -2463,6 +2653,8 @@ replica_abort_task_thread(void *arg)
release_it = 1;
}
+ cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Aborting task for rid(%d)...",data->rid);
+
/*
* Now send the cleanruv extended op to all the agreements
*/
@@ -2522,8 +2714,12 @@ done:
/*
* Clean up the config
*/
- delete_aborted_rid(data->replica, data->rid, data->repl_root);
- cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Successfully aborted cleanAllRUV task for rid(%d)", data->rid);
+ delete_aborted_rid(data->replica, data->rid, data->repl_root, 1); /* delete just the config, leave rid in memory */
+ if(strcasecmp(data->certify, "yes") == 0){
+ check_replicas_are_done_aborting(data);
+ }
+ delete_aborted_rid(data->replica, data->rid, data->repl_root, 0); /* remove the in-memory aborted rid */
+ cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Successfully aborted task for rid(%d)", data->rid);
}
if(data->task){
slapi_task_finish(data->task, agmt_not_notified);
@@ -2545,7 +2741,7 @@ replica_cleanallruv_send_abort_extop(Repl_Agmt *ra, Slapi_Task *task, struct ber
Repl_Connection *conn = NULL;
ConnResult crc = 0;
int msgid = 0;
- int rc = 0;
+ int rc = -1;
if((conn = conn_new(ra)) == NULL){
return -1;
@@ -2570,178 +2766,243 @@ replica_cleanallruv_send_abort_extop(Repl_Agmt *ra, Slapi_Task *task, struct ber
static int
-replica_cleanallruv_send_extop(Repl_Agmt *ra, ReplicaId rid, Slapi_Task *task, struct berval *payload, int check_result)
+replica_cleanallruv_send_extop(Repl_Agmt *ra, cleanruv_data *clean_data, int check_result)
{
Repl_Connection *conn = NULL;
ConnResult crc = 0;
int msgid = 0;
- int rc = 0;
+ int rc = -1;
if((conn = conn_new(ra)) == NULL){
return -1;
}
if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
- crc = conn_send_extended_operation(conn, REPL_CLEANRUV_OID, payload, NULL, &msgid);
+ crc = conn_send_extended_operation(conn, REPL_CLEANRUV_OID, clean_data->payload, NULL, &msgid);
if(crc == CONN_OPERATION_SUCCESS && check_result){
struct berval *retsdata = NULL;
char *retoid = NULL;
crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
if (CONN_OPERATION_SUCCESS == crc ){
- struct berval **ruv_bervals = NULL;
- struct berval *data = NULL;
- char *data_guid = NULL;
-
- decode_repl_ext_response(retsdata, &rc, &ruv_bervals, &data_guid, &data);
- /* just free everything, we only wanted "rc" */
- slapi_ch_free_string(&data_guid);
- if(data)
- ber_bvfree(data);
- if (ruv_bervals)
- ber_bvecfree(ruv_bervals);
-
- if(rc == 0 ){ /* rc == 1 is success */
- cleanruv_log(task, CLEANALLRUV_ID,"Replica %s does not support the CLEANALLRUV task. Sending replica CLEANRUV task...",
+ char *response = NULL;
+
+ decode_cleanruv_payload(retsdata, &response);
+ if(response && strcmp(response,CLEANRUV_ACCEPTED) == 0){
+ /* extop was accepted */
+ rc = 0;
+ } else {
+ cleanruv_log(clean_data->task, CLEANALLRUV_ID,"Replica %s does not support the CLEANALLRUV task. Sending replica CLEANRUV task...",
slapi_sdn_get_dn(agmt_get_dn_byref(ra)));
/*
* Ok, this replica doesn't know about CLEANALLRUV, so just manually
* add the CLEANRUV task to the replica.
*/
- replica_send_cleanruv_task(ra, rid, task);
- } else {
- /* extop was accepted */
- rc = 0;
+ replica_send_cleanruv_task(ra, clean_data);
}
- if (NULL != retoid)
- ldap_memfree(retoid);
+ slapi_ch_free_string(&retoid);
+ slapi_ch_free_string(&response);
if (NULL != retsdata)
ber_bvfree(retsdata);
}
- agmt_set_cleanruv_data(ra, rid, CLEANRUV_NOTIFIED);
} else {
/*
* success or failure, just return the error code
*/
rc = crc;
}
- } else {
- rc =-1;
}
conn_delete_internal_ext(conn);
return rc;
}
+static CSN*
+replica_cleanallruv_find_maxcsn(Replica *replica, ReplicaId rid, char *basedn)
+{
+ Object *agmt_obj;
+ Repl_Agmt *agmt;
+ char *rid_text;
+ CSN *maxcsn = NULL, *topcsn = NULL;
+ int done = 1, found = 0;
+ int interval = 10;
+
+ rid_text = slapi_ch_smprintf("%d", rid);
+
+ while(done && !is_task_aborted(rid) && !slapi_is_shutting_down()){
+ agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
+ if(agmt_obj == NULL){
+ break;
+ }
+ while (agmt_obj && !slapi_is_shutting_down()){
+ agmt = (Repl_Agmt*)object_get_data (agmt_obj);
+ if(get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
+ agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
+ continue;
+ }
+ if(replica_cleanallruv_get_replica_maxcsn(agmt, rid_text, basedn, &maxcsn) == 0){
+ if(maxcsn == NULL){
+ agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
+ continue;
+ }
+ found = 1;
+ if(topcsn == NULL){
+ topcsn = maxcsn;
+ } else {
+ if(csn_compare(topcsn, maxcsn) < 0){
+ csn_free(&topcsn);
+ topcsn = maxcsn;
+ } else {
+ csn_free(&maxcsn);
+ }
+ }
+ done = 0;
+ } else {
+ done = 1;
+ break;
+ }
+ agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
+ } /* agmt while */
+
+ if(done == 0 || is_task_aborted(rid) ){
+ break;
+ }
+ if(!found){
+ /* we could not find any maxcsn's - already cleaned? */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: could not find a maxcsn\n");
+ return NULL;
+ }
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: replica_cleanallruv_find_maxcsn: Not all replicas online, retrying in %d seconds\n",interval);
+ PR_Lock( notify_lock );
+ PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+ PR_Unlock( notify_lock );
+
+ if(interval < 14400){ /* 4 hour max */
+ interval = interval * 2;
+ } else {
+ interval = 14400;
+ }
+ }
+ slapi_ch_free_string(&rid_text);
+
+ if(is_task_aborted(rid)){
+ return NULL;
+ }
+
+ return topcsn;
+}
+
static int
-replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *rid_text, char *maxcsn, Slapi_Task *task)
+replica_cleanallruv_get_replica_maxcsn(Repl_Agmt *agmt, char *rid_text, char *basedn, CSN **csn)
{
Repl_Connection *conn = NULL;
- LDAP *ld;
- Slapi_DN *sdn;
- struct berval **vals;
- LDAPMessage *result = NULL, *entry = NULL;
- BerElement *ber;
- char *attrs[2];
- char *attr = NULL;
- char *iter = NULL;
- char *ruv_part = NULL;
- int found_rid = 0;
- int part_count = 0;
- int rc = 0, i;
+ ConnResult crc = 0;
+ struct berval *payload = NULL;
+ CSN *maxcsn = NULL;
+ char *data = NULL;
+ int msgid = 0;
if((conn = conn_new(agmt)) == NULL){
return -1;
}
+ data = slapi_ch_smprintf("%s:%s",rid_text, basedn);
+ payload = create_cleanruv_payload(data);
+
if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
- attrs[0] = "nsds50ruv";
- attrs[1] = NULL;
- ld = conn_get_ldap(conn);
- if(ld == NULL){
- conn_delete_internal_ext(conn);
- return -1;
- }
- sdn = agmt_get_replarea(agmt);
- rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(sdn), LDAP_SCOPE_SUBTREE,
- "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))",
- attrs, 0, NULL, NULL, NULL, 0, &result);
- slapi_sdn_free(&sdn);
- if(rc != LDAP_SUCCESS){
- cleanruv_log(task, CLEANALLRUV_ID,"Failed to contact "
- "agmt (%s) error (%d), will retry later.", agmt_get_long_name(agmt), rc);
- conn_delete_internal_ext(conn);
- return -1;
- }
- entry = ldap_first_entry( ld, result );
- if ( entry != NULL ) {
- for ( attr = ldap_first_attribute( ld, entry, &ber ); attr != NULL; attr = ldap_next_attribute( ld, entry, ber ) ){
- /* make sure the attribute is nsds50ruv */
- if(strcasecmp(attr,"nsds50ruv") != 0){
- ldap_memfree( attr );
- continue;
+ crc = conn_send_extended_operation(conn, REPL_CLEANRUV_GET_MAXCSN_OID, payload, NULL, &msgid);
+ if(crc == CONN_OPERATION_SUCCESS){
+ struct berval *retsdata = NULL;
+ char *retoid = NULL;
+
+ crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
+ if (CONN_OPERATION_SUCCESS == crc ){
+ char *remote_maxcsn = NULL;
+
+ decode_cleanruv_payload(retsdata, &remote_maxcsn);
+ if(remote_maxcsn && strcmp(remote_maxcsn, CLEANRUV_NO_MAXCSN)){
+ maxcsn = csn_new();
+ csn_init_by_string(maxcsn, remote_maxcsn);
+ *csn = maxcsn;
+ } else {
+ /* no csn */
+ *csn = NULL;
}
- found_rid = 0;
- if ((vals = ldap_get_values_len( ld, entry, attr)) != NULL ) {
- for ( i = 0; vals[i] && vals[i]->bv_val; i++ ) {
- /* look for this replica */
- if(strstr(vals[i]->bv_val, rid_text)){
- found_rid = 1;
- /* get the max csn compare it to our known max csn */
- ruv_part = ldap_utf8strtok_r(vals[i]->bv_val, " ", &iter);
- for(part_count = 1; ruv_part && part_count < 5; part_count++){
- ruv_part = ldap_utf8strtok_r(iter, " ", &iter);
- }
- if(part_count == 5 && ruv_part){/* we have the maxcsn */
- CSN *max, *repl_max;
-
- max = csn_new();
- repl_max = csn_new();
- csn_init_by_string(max, maxcsn);
- csn_init_by_string(repl_max, ruv_part);
- if(csn_compare (repl_max, max) < 0){
- /* we are not caught up yet, free, and return */
- cleanruv_log(task, CLEANALLRUV_ID,"Replica maxcsn (%s) not caught up deleted replica's maxcsn(%s)",
- ruv_part, maxcsn);
- ldap_value_free_len(vals);
- ldap_memfree( attr );
- ldap_msgfree( result );
- if(ber){
- ber_free( ber, 0 );
- }
- conn_delete_internal_ext(conn);
- csn_free(&max);
- csn_free(&repl_max);
- return -1;
- } else {
- /* ok this replica has all the updates from the deleted replica */
- csn_free(&max);
- csn_free(&repl_max);
- rc = 0;
- }
- } else {
- /* there is no maxcsn for this rid - treat it as caught up */
- rc = 0;
- }
- }
- }
- if(!found_rid){
- /* must have been cleaned already */
+ slapi_ch_free_string(&retoid);
+ slapi_ch_free_string(&remote_maxcsn);
+ if (NULL != retsdata)
+ ber_bvfree(retsdata);
+ }
+ }
+ }
+ conn_delete_internal_ext(conn);
+ slapi_ch_free_string(&data);
+ if(payload)
+ ber_bvfree(payload);
+
+ return (int)crc;
+}
+
+static int
+replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *basedn, char *rid_text, char *maxcsn, Slapi_Task *task)
+{
+ Repl_Connection *conn = NULL;
+ ConnResult crc = 0;
+ struct berval *payload = NULL;
+ char *data = NULL;
+ int msgid = 0;
+ int rc = -1;
+
+ if((conn = conn_new(agmt)) == NULL){
+ return -1;
+ }
+
+ data = slapi_ch_smprintf("%s:%s",rid_text, basedn);
+ payload = create_cleanruv_payload(data);
+
+ if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
+ crc = conn_send_extended_operation(conn, REPL_CLEANRUV_GET_MAXCSN_OID, payload, NULL, &msgid);
+ if(crc == CONN_OPERATION_SUCCESS){
+ struct berval *retsdata = NULL;
+ char *retoid = NULL;
+
+ crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
+ if (CONN_OPERATION_SUCCESS == crc ){
+ char *remote_maxcsn = NULL;
+
+ decode_cleanruv_payload(retsdata, &remote_maxcsn);
+ if(remote_maxcsn && strcmp(remote_maxcsn, CLEANRUV_NO_MAXCSN)){
+ CSN *max, *repl_max;
+
+ max = csn_new();
+ repl_max = csn_new();
+ csn_init_by_string(max, maxcsn);
+ csn_init_by_string(repl_max, remote_maxcsn);
+ if(csn_compare (repl_max, max) < 0){
+ /* we are not caught up yet, free, and return */
+ cleanruv_log(task, CLEANALLRUV_ID,"Replica maxcsn (%s) is not caught up with deleted replica's maxcsn(%s)",
+ remote_maxcsn, maxcsn);
+ rc = -1;
+ } else {
+ /* ok this replica is caught up */
rc = 0;
}
- ldap_value_free_len(vals);
+ csn_free(&max);
+ csn_free(&repl_max);
+ } else {
+ /* no remote_maxcsn - return success */
+ rc = 0;
}
- ldap_memfree( attr );
- }
- if ( ber != NULL ) {
- ber_free( ber, 0 );
+ slapi_ch_free_string(&retoid);
+ slapi_ch_free_string(&remote_maxcsn);
+ if (NULL != retsdata)
+ ber_bvfree(retsdata);
}
}
- if(result)
- ldap_msgfree( result );
- } else {
- rc = -1;
}
conn_delete_internal_ext(conn);
+ slapi_ch_free_string(&data);
+ if(payload)
+ ber_bvfree(payload);
return rc;
}
@@ -2752,7 +3013,7 @@ replica_cleanallruv_replica_alive(Repl_Agmt *agmt)
Repl_Connection *conn = NULL;
LDAP *ld = NULL;
LDAPMessage *result = NULL;
- int rc = 0;
+ int rc = -1;
if((conn = conn_new(agmt)) == NULL){
return -1;
@@ -2760,7 +3021,7 @@ replica_cleanallruv_replica_alive(Repl_Agmt *agmt)
if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
ld = conn_get_ldap(conn);
if(ld == NULL){
- slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanAllRUV_task: failed to get LDAP "
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "CleanAllRUV_task: failed to get LDAP "
"handle from the replication agmt (%s). Moving on to the next agmt.\n",agmt_get_long_name(agmt));
conn_delete_internal_ext(conn);
return -1;
@@ -2774,8 +3035,6 @@ replica_cleanallruv_replica_alive(Repl_Agmt *agmt)
}
if(result)
ldap_msgfree( result );
- } else {
- rc = -1;
}
conn_delete_internal_ext(conn);
@@ -2783,83 +3042,52 @@ replica_cleanallruv_replica_alive(Repl_Agmt *agmt)
}
static int
-replica_cleanallruv_check_ruv(Repl_Agmt *ra, char *rid_text, Slapi_Task *task)
+replica_cleanallruv_check_ruv(Repl_Agmt *agmt, char *rid_text, Slapi_Task *task)
{
Repl_Connection *conn = NULL;
- BerElement *ber = NULL;
- struct berval **vals = NULL;
- LDAPMessage *result = NULL, *entry = NULL;
- LDAP *ld = NULL;
- Slapi_DN *sdn;
- char *attrs[2];
- char *attr = NULL;
- int rc = 0, i;
+ ConnResult crc = 0;
+ struct berval *payload = NULL;
+ char *data = NULL;
+ int msgid = 0;
+ int rc = -1;
- if((conn = conn_new(ra)) == NULL){
+ if((conn = conn_new(agmt)) == NULL){
return -1;
}
+
+ data = slapi_ch_smprintf("%s:%s",rid_text, slapi_sdn_get_dn(agmt_get_replarea_by_ref(agmt)));
+
+ payload = create_cleanruv_payload(data);
+
if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
- attrs[0] = "nsds50ruv";
- attrs[1] = NULL;
- ld = conn_get_ldap(conn);
- if(ld == NULL){
- cleanruv_log(task, CLEANALLRUV_ID,"Failed to get LDAP handle from "
- "the replication agmt (%s). Moving on to the next agmt.",agmt_get_long_name(ra));
- rc = -1;
- goto done;
- }
+ crc = conn_send_extended_operation(conn, REPL_CLEANRUV_GET_MAXCSN_OID, payload, NULL, &msgid);
+ if(crc == CONN_OPERATION_SUCCESS){
+ struct berval *retsdata = NULL;
+ char *retoid = NULL;
- sdn = agmt_get_replarea(ra);
- rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(sdn), LDAP_SCOPE_SUBTREE,
- "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))",
- attrs, 0, NULL, NULL, NULL, 0, &result);
- slapi_sdn_free(&sdn);
- if(rc != LDAP_SUCCESS){
- cleanruv_log(task, CLEANALLRUV_ID,"Failed to contact "
- "agmt (%s) error (%d), will retry later.", agmt_get_long_name(ra), rc);
- rc = -1;
- goto done;
- }
- entry = ldap_first_entry( ld, result );
- if ( entry != NULL ) {
- for ( attr = ldap_first_attribute( ld, entry, &ber ); attr != NULL; attr = ldap_next_attribute( ld, entry, ber ) ){
- /* make sure the attribute is nsds50ruv */
- if(strcasecmp(attr,"nsds50ruv") != 0){
- ldap_memfree( attr );
- continue;
- }
- if ((vals = ldap_get_values_len( ld, entry, attr)) != NULL ) {
- for ( i = 0; vals[i] && vals[i]->bv_val; i++ ) {
- /* look for this replica */
- if(strstr(vals[i]->bv_val, rid_text)){
- /* rid has not been cleaned yet, free and return */
- rc = -1;
- ldap_value_free_len(vals);
- ldap_memfree( attr );
- if ( ber != NULL ) {
- ber_free( ber, 0 );
- ber = NULL;
- }
- goto done;
- } else {
- rc = 0;
- }
- }
- ldap_value_free_len(vals);
+ crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
+ if (CONN_OPERATION_SUCCESS == crc ){
+ char *remote_maxcsn = NULL;
+
+ decode_cleanruv_payload(retsdata, &remote_maxcsn);
+ if(remote_maxcsn && strcmp(remote_maxcsn, CLEANRUV_NO_MAXCSN)){
+ /* remote replica still has dirty RUV element */
+ rc = -1;
+ } else {
+ /* no maxcsn = we're clean */
+ rc = 0;
}
- ldap_memfree( attr );
- } /* for loop */
- if ( ber != NULL ) {
- ber_free( ber, 0 );
+ slapi_ch_free_string(&retoid);
+ slapi_ch_free_string(&remote_maxcsn);
+ if (NULL != retsdata)
+ ber_bvfree(retsdata);
}
}
-done:
- if(result)
- ldap_msgfree( result );
- } else {
- return -1;
}
conn_delete_internal_ext(conn);
+ slapi_ch_free_string(&data);
+ if(payload)
+ ber_bvfree(payload);
return rc;
}
diff --git a/ldap/servers/plugins/replication/repl_extop.c b/ldap/servers/plugins/replication/repl_extop.c
index 8026ff4..1e6f29a 100644
--- a/ldap/servers/plugins/replication/repl_extop.c
+++ b/ldap/servers/plugins/replication/repl_extop.c
@@ -1382,7 +1382,6 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
cleanruv_data *data;
Replica *r;
ReplicaId rid;
- CSN *maxcsn = NULL;
struct berval *extop_payload = NULL;
char *extop_oid;
char *repl_root;
@@ -1394,7 +1393,7 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_payload);
- if (NULL == extop_oid || strcmp(extop_oid, REPL_CLEANRUV_OID) != 0 ||
+ if (NULL == extop_oid || strcmp(extop_oid, REPL_ABORT_CLEANRUV_OID) != 0 ||
NULL == extop_payload || NULL == extop_payload->bv_val){
/* something is wrong, error out */
return LDAP_OPERATIONS_ERROR;
@@ -1403,24 +1402,25 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
* Decode the payload, and grab our settings
*/
if(decode_cleanruv_payload(extop_payload, &payload)){
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: failed to decode payload. Aborting ext op\n");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to decode payload. Aborting ext op\n");
return LDAP_OPERATIONS_ERROR;
}
rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
repl_root = ldap_utf8strtok_r(iter, ":", &iter);
certify_all = ldap_utf8strtok_r(iter, ":", &iter);
- if(!is_cleaned_rid(rid) || is_task_aborted(rid)){
+ if(!is_cleaned_rid(rid) || !is_pre_cleaned_rid(rid) || is_task_aborted(rid)){
/* This replica has already been aborted, or was never cleaned, or already finished cleaning */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: rid is not being cleaned. Aborting abort task.\n");
goto out;
} else {
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: aborting cleanallruv task for rid(%d)\n", rid);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: aborting cleanallruv task for rid(%d)\n", rid);
}
/*
* Get the node, so we can get the replica and its agreements
*/
if((mtnode_ext = replica_config_get_mtnode_by_dn(repl_root)) == NULL){
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: failed to get replication node "
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to get replication node "
"from (%s), aborting operation\n", repl_root);
rc = LDAP_OPERATIONS_ERROR;
goto out;
@@ -1429,14 +1429,14 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
object_acquire (mtnode_ext->replica);
release_it = 1;
} else {
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: replica is missing from (%s), "
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: replica is missing from (%s), "
"aborting operation\n",repl_root);
rc = LDAP_OPERATIONS_ERROR;
goto out;
}
r = (Replica*)object_get_data (mtnode_ext->replica);
if(r == NULL){
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: replica is NULL, aborting task\n");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: replica is NULL, aborting task\n");
rc = LDAP_OPERATIONS_ERROR;
goto out;
}
@@ -1445,7 +1445,7 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
*/
data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
if (data == NULL) {
- slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name, "Abort cleanAllRUV task: failed to allocate "
+ slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name, "Abort CleanAllRUV Task: failed to allocate "
"abort_cleanruv_data. Aborting task.\n");
rc = LDAP_OPERATIONS_ERROR;
goto out;
@@ -1459,11 +1459,8 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
data->repl_root = slapi_ch_strdup(repl_root);
data->certify = slapi_ch_strdup(certify_all);
/*
- * Stop the cleaning, and delete the rid
+ * Set the aborted rid and stop the cleaning
*/
- maxcsn = replica_get_cleanruv_maxcsn(r, rid);
- delete_cleaned_rid(r, rid, maxcsn);
- csn_free(&maxcsn);
add_aborted_rid(rid, r, repl_root);
stop_ruv_cleaning();
/*
@@ -1473,7 +1470,7 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
if (thread == NULL) {
- slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name, "Abort cleanAllRUV task: unable to create abort "
+ slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name, "Abort CleanAllRUV Task: unable to create abort "
"thread. Aborting task.\n");
release_it = 1; /* have to release mtnode_ext->replica now */
slapi_ch_free_string(&data->repl_root);
@@ -1514,10 +1511,10 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
struct berval *extop_payload;
struct berval *resp_bval = NULL;
BerElement *resp_bere = NULL;
- char *extop_oid;
- char *repl_root;
char *payload = NULL;
char *csnstr = NULL;
+ char *extop_oid;
+ char *repl_root;
char *iter;
char *force = NULL;
int release_it = 0;
@@ -1536,7 +1533,7 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
* Decode the payload
*/
if(decode_cleanruv_payload(extop_payload, &payload)){
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: failed to decode payload. Aborting ext op\n");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to decode payload. Aborting ext op\n");
goto free_and_return;
}
rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
@@ -1551,33 +1548,30 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
/*
* If we already cleaned this server, just return success
*/
- if(is_cleaned_rid(rid) || is_pre_cleaned_rid(rid)){
+ if(is_cleaned_rid(rid) || is_pre_cleaned_rid(rid) || is_task_aborted(rid)){
csn_free(&maxcsn);
rc = LDAP_SUCCESS;
goto free_and_return;
}
-
/*
* Get the node, so we can get the replica and its agreements
*/
if((mtnode_ext = replica_config_get_mtnode_by_dn(repl_root)) == NULL){
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: failed to get replication node "
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to get replication node "
"from (%s), aborting operation\n", repl_root);
goto free_and_return;
}
-
if (mtnode_ext->replica){
object_acquire (mtnode_ext->replica);
release_it = 1;
} else {
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: replica is missing from (%s), "
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: replica is missing from (%s), "
"aborting operation\n",repl_root);
goto free_and_return;
}
-
r = (Replica*)object_get_data (mtnode_ext->replica);
if(r == NULL){
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: replica is NULL, aborting task\n");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: replica is NULL, aborting task\n");
goto free_and_return;
}
@@ -1587,10 +1581,10 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
*
* This will also release mtnode_ext->replica
*/
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: launching cleanAllRUV thread...\n");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: launching cleanAllRUV thread...\n");
data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
if (data == NULL) {
- slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: failed to allocate "
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to allocate "
"cleanruv_Data\n");
goto free_and_return;
}
@@ -1601,16 +1595,18 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
data->maxcsn = maxcsn;
data->payload = slapi_ch_bvdup(extop_payload);
data->force = slapi_ch_strdup(force);
+ data->repl_root = slapi_ch_strdup(repl_root);
thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread_ext,
(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
if (thread == NULL) {
- slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: unable to create cleanAllRUV "
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: unable to create cleanAllRUV "
"monitoring thread. Aborting task.\n");
ber_bvfree(data->payload);
data->payload = NULL;
slapi_ch_free_string(&data->force);
+ slapi_ch_free_string(&data->repl_root);
slapi_ch_free((void **)&data);
} else {
release_it = 0; /* thread will release data->repl_obj == mtnode_ext->replica */
@@ -1632,18 +1628,18 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
/* we've already been cleaned */
break;
}
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: checking if we're caught up...\n");
- if(ruv_covers_csn_cleanallruv(ruv,maxcsn) || csn_get_replicaid(maxcsn) == 0){
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: checking if we're caught up...\n");
+ if(ruv_covers_csn_cleanallruv(ruv,maxcsn) || csn_get_replicaid(maxcsn) == 0 || strcmp(force,"yes") == 0){
/* We are caught up */
break;
} else {
char csnstr[CSN_STRSIZE];
csn_as_string(maxcsn, PR_FALSE, csnstr);
- slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: ruv not caught up to maxcsn(%s)\n", csnstr);
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: ruv not caught up to maxcsn(%s)\n", csnstr);
}
DS_Sleep(PR_SecondsToInterval(5));
}
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: we're caught up...\n");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: we're caught up...\n");
/*
* Set cleaned rid in memory only - does not survive a server restart
*/
@@ -1659,8 +1655,8 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
* This read-only replica has no easy way to tell when it's safe to release the rid.
* So we won't release it, not until a server restart.
*/
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: You must restart the server if you want to reuse rid(%d).\n", rid);
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV Task: Successfully cleaned rid(%d).\n", rid);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: You must restart the server if you want to reuse rid(%d).\n", rid);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: Successfully cleaned rid(%d).\n", rid);
rc = LDAP_SUCCESS;
}
@@ -1675,10 +1671,123 @@ free_and_return:
* Craft a message so we know this replica supports the task
*/
if ((resp_bere = der_alloc())){
+ ber_printf(resp_bere, "{s}", CLEANRUV_ACCEPTED);
+ ber_flatten(resp_bere, &resp_bval);
+ slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
+ slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
+ /* resp_bere */
+ if (NULL != resp_bere)
+ {
+ ber_free(resp_bere, 1);
+ }
+ /* resp_bval */
+ if (NULL != resp_bval)
+ {
+ ber_bvfree(resp_bval);
+ }
+ /* tell extendop code that we have already sent the result */
+ rc = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
+ } else {
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+
+ return rc;
+}
+
+/*
+ * Get the max csn for the designated repl area
+ */
+int
+multimaster_extop_cleanruv_get_maxcsn(Slapi_PBlock *pb)
+{
+ Slapi_PBlock *search_pb = NULL;
+ Slapi_Entry **entries = NULL;
+ struct berval *resp_bval = NULL;
+ struct berval *extop_payload;
+ BerElement *resp_bere = NULL;
+ char **ruv_elements = NULL;
+ char *extop_oid = NULL;
+ char *ruv_part = NULL;
+ char *base_dn = NULL;
+ char *payload = NULL;
+ char *maxcsn = NULL;
+ char *filter = NULL;
+ char *ridstr = NULL;
+ char *iter = NULL;
+ char *attrs[2];
+ int part_count = 0;
+ int rid = 0;
+ int res = 0;
+ int rc = LDAP_OPERATIONS_ERROR;
+ int i = 0;
+
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_payload);
+
+ if (NULL == extop_oid || strcmp(extop_oid, REPL_CLEANRUV_GET_MAXCSN_OID) != 0 ||
+ NULL == extop_payload || NULL == extop_payload->bv_val){
+ /* something is wrong, error out */
+ goto free_and_return;
+ }
+ /*
+ * Decode the payload
+ */
+ if(decode_cleanruv_payload(extop_payload, &payload)){
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Get MaxCSN Task: failed to decode payload. Aborting ext op\n");
+ goto free_and_return;
+ }
+ rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
+ base_dn = ldap_utf8strtok_r(iter, ":", &iter);
- ber_int_t response = 1;
+ /*
+ * Get the maxruv from the database tombstone entry
+ */
+ filter = "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))";
+ attrs[0] = "nsds50ruv";
+ attrs[1] = NULL;
+ ridstr = slapi_ch_smprintf("{replica %d ldap", rid);
+
+ search_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(search_pb, base_dn, LDAP_SCOPE_SUBTREE, filter, attrs, 0, NULL, NULL, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_search_internal_pb (search_pb);
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+
+ if ( LDAP_SUCCESS == res ) {
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || entries[0] == NULL) {
+ /* Hmmm, no tombstpne! Error out */
+ } else {
+ /* find the right ruv element, and find the maxcsn */
+ ruv_elements = slapi_entry_attr_get_charray(entries[0],attrs[0]);
+ for(i = 0; ruv_elements && ruv_elements[i] ; i++){
+ if(strstr(ruv_elements[i], ridstr)){
+ /* get the max csn */
+ ruv_part = ldap_utf8strtok_r(ruv_elements[i], " ", &iter);
+ for(part_count = 1; ruv_part && part_count < 5; part_count++){
+ ruv_part = ldap_utf8strtok_r(iter, " ", &iter);
+ }
+ if(part_count == 5 && ruv_part){/* we have the maxcsn */
+ maxcsn = slapi_ch_strdup(ruv_part);
+ break;
+ }
+ }
+ }
+ slapi_ch_array_free(ruv_elements);
+ }
+ } else {
+ /* internal search failed */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Get MaxCSN Task: internal search failed (%d)\n", res);
+ }
+ if(maxcsn == NULL){
+ maxcsn = slapi_ch_strdup(CLEANRUV_NO_MAXCSN);
+ }
- ber_printf(resp_bere, "{e}", response);
+ /*
+ * Send the extended op response
+ */
+ if ((resp_bere = der_alloc())){
+
+ ber_printf(resp_bere, "{s}", maxcsn);
ber_flatten(resp_bere, &resp_bval);
slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
@@ -1698,10 +1807,96 @@ free_and_return:
rc = LDAP_OPERATIONS_ERROR;
}
+free_and_return:
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(search_pb);
+ slapi_ch_free_string(&payload);
+ slapi_ch_free_string(&maxcsn);
+ slapi_ch_free_string(&ridstr);
+
return rc;
}
/*
+ * Search cn=config for the cleanallruv attributes (clean & abort)
+ */
+int
+multimaster_extop_cleanruv_check_status(Slapi_PBlock *pb)
+{
+ Slapi_PBlock *search_pb = NULL;
+ Slapi_Entry **entries = NULL;
+ struct berval *resp_bval = NULL;
+ struct berval *extop_payload;
+ BerElement *resp_bere = NULL;
+ char *response = NULL;
+ char *filter = NULL;
+ char *extop_oid;
+ int res = 0;
+ int rc = LDAP_OPERATIONS_ERROR;
+
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_payload);
+
+ if (NULL == extop_oid || strcmp(extop_oid, REPL_CLEANRUV_CHECK_STATUS_OID) != 0 ||
+ NULL == extop_payload || NULL == extop_payload->bv_val){
+ /* something is wrong, error out */
+ goto free_and_return;
+ }
+ /*
+ * Decode the payload - which should just be a filter
+ */
+ if(decode_cleanruv_payload(extop_payload, &filter)){
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Check Status Task: failed to decode payload. Aborting ext op\n");
+ goto free_and_return;
+ }
+
+ search_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(search_pb, "cn=config", LDAP_SCOPE_SUBTREE,
+ filter, NULL, 0, NULL, NULL, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_search_internal_pb (search_pb);
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+
+ if ( LDAP_SUCCESS == res ) {
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || entries[0] == NULL) {
+ /* cleaning task has finished, send repsonse */
+ response = CLEANRUV_FINISHED;
+ } else {
+ response = CLEANRUV_CLEANING;
+ }
+
+ /*
+ * Send the extended op response
+ */
+ if ((resp_bere = der_alloc())){
+ ber_printf(resp_bere, "{s}", response);
+ ber_flatten(resp_bere, &resp_bval);
+ slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
+ slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
+ /* resp_bere */
+ if (NULL != resp_bere)
+ {
+ ber_free(resp_bere, 1);
+ }
+ /* resp_bval */
+ if (NULL != resp_bval)
+ {
+ ber_bvfree(resp_bval);
+ }
+ /* tell extendop code that we have already sent the result */
+ rc = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
+ }
+ }
+
+free_and_return:
+
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(search_pb);
+ slapi_ch_free_string(&filter);
+
+ return rc;
+}
+/*
* This plugin entry point is a noop entry
* point. It's used when registering extops that
* are only used as responses. We'll never receive
diff --git a/ldap/servers/plugins/replication/replutil.c b/ldap/servers/plugins/replication/replutil.c
index 3eec20a..7150d33 100644
--- a/ldap/servers/plugins/replication/replutil.c
+++ b/ldap/servers/plugins/replication/replutil.c
@@ -788,7 +788,7 @@ repl_set_mtn_state_and_referrals(
}
}
- if (rc != LDAP_SUCCESS) {
+ if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS) {
char ebuf[BUFSIZ];
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "repl_set_mtn_referrals: could "
"not set referrals for replica %s: %d\n",
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index ca8216f..0f1db5e 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -71,6 +71,11 @@ void modify_init(modify_context *mc,struct backentry *old_entry)
int modify_apply_mods(modify_context *mc, Slapi_Mods *smods)
{
+ return modify_apply_mods_ignore_error(mc, smods, -1);
+}
+
+int modify_apply_mods_ignore_error(modify_context *mc, Slapi_Mods *smods, int error)
+{
int ret = 0;
/* Make a copy of the entry */
PR_ASSERT(mc->old_entry != NULL);
@@ -78,9 +83,10 @@ int modify_apply_mods(modify_context *mc, Slapi_Mods *smods)
mc->new_entry = backentry_dup(mc->old_entry);
PR_ASSERT(smods!=NULL);
if ( mods_have_effect (mc->new_entry->ep_entry, smods) ) {
- ret = entry_apply_mods( mc->new_entry->ep_entry, slapi_mods_get_ldapmods_byref(smods));
+ ret = entry_apply_mods_ignore_error( mc->new_entry->ep_entry, slapi_mods_get_ldapmods_byref(smods), error);
}
mc->smods= smods;
+
return ret;
}
diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c
index 8140818..3ef3ab7 100644
--- a/ldap/servers/slapd/back-ldbm/misc.c
+++ b/ldap/servers/slapd/back-ldbm/misc.c
@@ -444,9 +444,9 @@ ldbm_txn_ruv_modify_context( Slapi_PBlock *pb, modify_context *mc )
modify_init( mc, bentry );
- if (modify_apply_mods( mc, smods )) {
- LDAPDebug( LDAP_DEBUG_ANY, "Error: ldbm_txn_ruv_modify_context failed to apply updates to RUV entry\n",
- 0, 0, 0 );
+ if (modify_apply_mods_ignore_error( mc, smods, LDAP_TYPE_OR_VALUE_EXISTS )) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Error: ldbm_txn_ruv_modify_context failed to apply updates to RUV entry(%s)\n",
+ backentry_get_ndn(mc->old_entry), 0 , 0 );
rc = -1;
modify_term( mc, be );
}
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index 0734162..e07ab6e 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -343,6 +343,7 @@ int get_parent_rdn(DB *db, ID parentid, Slapi_RDN *srdn);
int modify_update_all(backend *be, Slapi_PBlock *pb,modify_context *mc,back_txn *txn);
void modify_init(modify_context *mc,struct backentry *old_entry);
int modify_apply_mods(modify_context *mc, Slapi_Mods *smods);
+int modify_apply_mods_ignore_error(modify_context *mc, Slapi_Mods *smods, int error);
int modify_term(modify_context *mc,backend *be);
int modify_switch_entries(modify_context *mc,backend *be);
diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c
index 08b9066..1f40072 100644
--- a/ldap/servers/slapd/entry.c
+++ b/ldap/servers/slapd/entry.c
@@ -3261,6 +3261,15 @@ int slapi_entry_apply_mod( Slapi_Entry *e, LDAPMod *mod )
int
entry_apply_mods( Slapi_Entry *e, LDAPMod **mods )
{
+ return entry_apply_mods_ignore_error(e, mods, -1);
+}
+
+/*
+ * If one of the mods fails due to the specified error, ignore it.
+ */
+int
+entry_apply_mods_ignore_error( Slapi_Entry *e, LDAPMod **mods, int ignore_error )
+{
int err;
LDAPMod **mp = NULL;
@@ -3270,7 +3279,9 @@ entry_apply_mods( Slapi_Entry *e, LDAPMod **mods )
for ( mp = mods; mp && *mp; mp++ )
{
err = entry_apply_mod( e, *mp );
- if ( err != LDAP_SUCCESS ) {
+ if(err == ignore_error){
+ (*mp)->mod_op = LDAP_MOD_IGNORE;
+ } else if ( err != LDAP_SUCCESS ) {
break;
}
}
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
index db4a317..504425d 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -330,6 +330,7 @@ int entry_next_deleted_attribute( const Slapi_Entry *e, Slapi_Attr **a);
/* entry.c */
int entry_apply_mods( Slapi_Entry *e, LDAPMod **mods );
+int entry_apply_mods_ignore_error( Slapi_Entry *e, LDAPMod **mods, int ignore_error );
int is_type_protected(const char *type);
int slapi_entries_diff(Slapi_Entry **old_entries, Slapi_Entry **new_entries, int testall, const char *logging_prestr, const int force_update, void *plg_id);