Branch '389-ds-base-1.2.10' - ldap/servers
by Mark Reynolds
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);
11 years, 5 months
ldap/servers
by Mark Reynolds
ldap/servers/plugins/replication/cl5_api.c | 21
ldap/servers/plugins/replication/repl5.h | 29
ldap/servers/plugins/replication/repl5_agmt.c | 99 -
ldap/servers/plugins/replication/repl5_agmtlist.c | 11
ldap/servers/plugins/replication/repl5_connection.c | 6
ldap/servers/plugins/replication/repl5_init.c | 69 +
ldap/servers/plugins/replication/repl5_replica.c | 132 --
ldap/servers/plugins/replication/repl5_replica_config.c | 1055 ++++++++++------
ldap/servers/plugins/replication/repl_extop.c | 266 +++-
ldap/servers/plugins/replication/replutil.c | 47
ldap/servers/slapd/back-ldbm/ldbm_modify.c | 7
ldap/servers/slapd/back-ldbm/misc.c | 2
ldap/servers/slapd/back-ldbm/proto-back-ldbm.h | 1
ldap/servers/slapd/entry.c | 10
ldap/servers/slapd/slapi-private.h | 2
15 files changed, 1104 insertions(+), 653 deletions(-)
New commits:
commit ecbd8b7513d05dab5876a88ca56b102c08a7a67c
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Tue Nov 20 16:14:42 2012 -0500
Ticket 337 - improve CLEANRUV functionality
Bug Description: Without anonymous access allowed, then task could not
contact other servers and retrieve data(ruv, maxcsns, etc).
Fix Description: Changed all communication to use extended operations, and improved
sychronization between the replicas.
https://fedorahosted.org/389/ticket/337
Reviewed by: richm(Thanks Rich!)
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index a347c57..6c94b3d 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -1474,13 +1474,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
@@ -1488,14 +1488,14 @@ 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
of the supplier's ruv not in the consumer's ruv put min csn from the
supplier's ruv into the list. The list contains, for each known replica,
the starting point for changes to be sent to the consumer.
- Sort the list in accending order.
+ Sort the list in ascending order.
Build a hash which contains, for each known replica, whether the
supplier can bring the consumer up to data with respect to that replica.
The hash is used to decide whether a change can be sent to the consumer
@@ -1503,7 +1503,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,
@@ -6543,7 +6543,9 @@ bail:
void
cl5CleanRUV(ReplicaId rid){
CL5DBFile *file;
- Object *obj;
+ Object *obj = NULL;
+
+ slapi_rwlock_wrlock (s_cl5Desc.stLock);
obj = objset_first_obj(s_cl5Desc.dbFiles);
while (obj){
@@ -6552,6 +6554,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 aa7684c..4c57ee5 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 */
@@ -239,6 +245,8 @@ 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);
@@ -374,9 +382,6 @@ PRBool agmt_is_enabled(Repl_Agmt *ra);
int agmt_set_enabled_from_entry(Repl_Agmt *ra, Slapi_Entry *e, char *returntext);
char **agmt_get_attrs_to_strip(Repl_Agmt *ra);
int agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e);
-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);
int agmt_set_timeout(Repl_Agmt *ra, long timeout);
void agmt_update_done(Repl_Agmt *ra, int is_total);
@@ -463,6 +468,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;
@@ -617,7 +623,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);
@@ -625,17 +631,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);
-void delete_aborted_rid(Replica *replica, ReplicaId rid, char *repl_root);
+void delete_aborted_rid(Replica *replica, ReplicaId rid, char *repl_root, int skip);
+int is_pre_cleaned_rid(ReplicaId rid);
void set_cleaned_rid(ReplicaId rid);
void cleanruv_log(Slapi_Task *task, char *task_type, char *fmt, ...);
@@ -652,6 +656,7 @@ typedef struct _cleanruv_data
char *repl_root;
Slapi_DN *sdn;
char *certify;
+ char *force;
} cleanruv_data;
/* replutil.c */
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
index d25f54b..935fb37 100644
--- a/ldap/servers/plugins/replication/repl5_agmt.c
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
@@ -141,7 +141,6 @@ typedef struct repl5agmt {
char **attrs_to_strip; /* for fractional replication, if a "mod" is empty, strip out these attributes:
* modifiersname, modifytimestamp, internalModifiersname, internalModifyTimestamp, etc */
int agreement_type;
- int cleanruv_notified[CLEANRIDSIZ + 1]; /* specifies if the replica has been notified of a CLEANALLRUV task */
} repl5agmt;
/* Forward declarations */
@@ -252,7 +251,6 @@ agmt_new_from_entry(Slapi_Entry *e)
Repl_Agmt *ra;
Slapi_Attr *sattr;
char *tmpstr;
- char **clean_vals = NULL;
char **denied_attrs = NULL;
char *auto_initialize = NULL;
char *val_nsds5BeginReplicaRefresh = "start";
@@ -431,20 +429,6 @@ agmt_new_from_entry(Slapi_Entry *e)
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);
@@ -2623,89 +2607,6 @@ agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e)
return -1;
}
-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);
-}
-
/* this is called whenever an update (total/incremental)
is completed */
void
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
index 537cfd8..70f71a8 100644
--- a/ldap/servers/plugins/replication/repl5_agmtlist.c
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
@@ -248,7 +248,12 @@ 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;
@@ -508,10 +513,6 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
rc = SLAPI_DSE_CALLBACK_ERROR;
}
}
- 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..5efd0e6 100644
--- a/ldap/servers/plugins/replication/repl5_connection.c
+++ b/ldap/servers/plugins/replication/repl5_connection.c
@@ -1760,6 +1760,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 59caf4a..cc73f5d 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
@@ -477,6 +494,52 @@ multimaster_end_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;
+}
+
int
multimaster_total_extop_init( Slapi_PBlock *pb )
@@ -813,6 +876,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 846881d..3d7677b 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];
};
@@ -310,7 +309,6 @@ replica_destroy(void **arg)
{
Replica *r;
void *repl_name;
- int i;
if (arg == NULL)
return;
@@ -397,10 +395,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);
}
@@ -1502,7 +1496,7 @@ int replica_check_for_data_reload (Replica *r, void *arg)
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_check_for_data_reload: "
"Warning: for replica %s there were some differences between the changelog max RUV and the "
"database RUV. If there are obsolete elements in the database RUV, you "
- "should remove them using CLEANRUV task. If they are not obsolete, "
+ "should remove them using the CLEANALLRUV task. If they are not obsolete, "
"you should check their status to see why there are no changes from those "
"servers in the changelog.\n",
slapi_sdn_get_dn(r->repl_root));
@@ -1819,12 +1813,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 *token = NULL;
- ReplicaId rid;
+ char *forcing;
+ char *csnpart;
+ char *ridstr;
+ char *iter;
int i;
for(i = 0; i < CLEANRIDSIZ && clean_vals[i]; i++){
@@ -1833,7 +1828,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);
@@ -1851,15 +1845,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);
+ 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){
@@ -1882,8 +1879,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,
@@ -1895,11 +1894,11 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
csn_free(&maxcsn);
slapi_sdn_free(&data->sdn);
ber_bvfree(data->payload);
+ slapi_ch_free_string(&data->force);
slapi_ch_free((void **)&data);
}
}
}
- r->repl_cleanruv_data[i] = NULL;
done:
slapi_ch_array_free(clean_vals);
@@ -1909,13 +1908,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++){
@@ -1926,21 +1924,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);
+
+ 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();
- maxcsn = replica_get_cleanruv_maxcsn(r, rid);
- delete_cleaned_rid(r, rid, maxcsn);
- csn_free(&maxcsn);
slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: abort task found, "
"resuming abort of rid(%d).\n", rid);
@@ -1951,8 +1955,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){
@@ -2583,7 +2587,7 @@ replica_ruv_smods_for_op( Slapi_PBlock *pb, char **uniqueid, Slapi_Mods **smods
must use the CLEANRUV task instead */
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
"replica_ruv_smods_for_op: attempted to directly modify the tombstone RUV "
- "entry [%s] - use the CLEANRUV task instead\n",
+ "entry [%s] - use the CLEANALLRUV task instead\n",
slapi_entry_get_dn_const(target_entry));
return (-1);
}
@@ -3430,7 +3434,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 "
@@ -3794,69 +3798,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 51ab2e3..f1baef2 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -64,6 +64,7 @@
int slapi_log_urp = SLAPI_LOG_REPL;
static ReplicaId cleaned_rids[CLEANRIDSIZ + 1] = {0};
+static ReplicaId pre_cleaned_rids[CLEANRIDSIZ + 1] = {0};
static ReplicaId aborted_rids[CLEANRIDSIZ + 1] = {0};
static Slapi_RWLock *rid_lock = NULL;
static Slapi_RWLock *abort_rid_lock = NULL;
@@ -84,20 +85,27 @@ static int replica_execute_task (Object *r, const char *task_name, char *returnt
static int replica_execute_cl2ldif_task (Object *r, char *returntext);
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, 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(cleanruv_data *data, char *maxcsn);
+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 replica_cleanallruv_check_ruv(char *repl_root, Repl_Agmt *ra, char *rid_text, Slapi_Task *task);
static int get_cleanruv_task_count();
static int get_abort_cleanruv_task_count();
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 void preset_cleaned_rid(ReplicaId rid);
static multimaster_mtnode_extension * _replica_config_get_mtnode_ext (const Slapi_Entry *e);
/*
@@ -385,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;
@@ -891,7 +905,7 @@ static int replica_execute_task (Object *r, const char *task_name, char *returnt
if (apply_mods)
{
Slapi_Task *empty_task = NULL;
- return replica_execute_cleanall_ruv_task(r, (ReplicaId)temprid, empty_task, returntext);
+ return replica_execute_cleanall_ruv_task(r, (ReplicaId)temprid, empty_task, returntext, "no");
}
else
return LDAP_SUCCESS;
@@ -1225,35 +1239,52 @@ 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;
- ReplicaId rid;
int rc = SLAPI_DSE_CALLBACK_OK;
/* allocate new task now */
task = slapi_new_task(slapi_entry_get_ndn(e));
+ task_dn = slapi_entry_get_sdn(e);
if(task == NULL){
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Failed to create new task\n");
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;
}
- task_dn = slapi_entry_get_sdn(e);
+ if ((force_cleaning = fetch_attr(e, "replica-force-cleaning", 0)) != NULL){
+ if(strcasecmp(force_cleaning,"yes") != 0 && strcasecmp(force_cleaning,"no") != 0){
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid value for replica-force-cleaning "
+ "(%s). Value must be \"yes\" or \"no\" for task - (%s)",
+ force_cleaning, slapi_sdn_get_dn(task_dn));
+ cleanruv_log(task, CLEANALLRUV_ID, "%s", returntext);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ } else {
+ force_cleaning = "no";
+ }
/*
* Check the rid
*/
@@ -1266,6 +1297,14 @@ replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
rc = SLAPI_DSE_CALLBACK_ERROR;
goto out;
}
+ if(is_cleaned_rid(rid)){
+ /* we are already cleaning this rid */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Replica id (%d) is already being cleaned", rid);
+ cleanruv_log(task, CLEANALLRUV_ID, "%s", returntext);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
/*
* Get the replica object
*/
@@ -1279,7 +1318,7 @@ replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
}
/* clean the RUV's */
- rc = replica_execute_cleanall_ruv_task (r, rid, task, returntext);
+ rc = replica_execute_cleanall_ruv_task (r, rid, task, force_cleaning, returntext);
out:
if(rc){
@@ -1302,31 +1341,36 @@ out:
*
*/
static int
-replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, char *returntext)
+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;
cleanruv_data *data = NULL;
+ PRThread *thread = NULL;
CSN *maxcsn = NULL;
- const RUV *ruv;
- struct berval *payload = NULL;
- char *ridstr = NULL;
+ Replica *replica;
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
*/
- replica = (Replica*)object_get_data (r);
+ if(r){
+ replica = (Replica*)object_get_data (r);
+ } else {
+ cleanruv_log(pre_task, CLEANALLRUV_ID, "Replica object is NULL, aborting task");
+ return -1;
+ }
/*
* Check if this is a consumer
*/
@@ -1342,32 +1386,25 @@ 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);
+ cleanruv_log(pre_task, CLEANALLRUV_ID, "Retrieving maxcsn...");
+ 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);
+ cleanruv_log(pre_task, CLEANALLRUV_ID, "Found maxcsn (%s)",csnstr);
/*
* Create payload
*/
- ridstr = slapi_ch_smprintf("%d:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(replica)), csnstr);
- payload = create_ruv_payload(ridstr);
+ ridstr = slapi_ch_smprintf("%d:%s:%s:%s", rid, basedn, csnstr, force_cleaning);
+ payload = create_cleanruv_payload(ridstr);
slapi_ch_free_string(&ridstr);
if(payload == NULL){
@@ -1389,15 +1426,19 @@ 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,
(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
if (thread == NULL) {
rc = -1;
+ slapi_ch_free_string(&data->force);
+ slapi_ch_free_string(&data->repl_root);
goto fail;
} else {
goto done;
@@ -1441,11 +1482,11 @@ 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;
@@ -1466,7 +1507,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){
@@ -1488,17 +1529,25 @@ 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);
-
/*
* Add the cleanallruv task to the repl config - so we can handle restarts
*/
+ add_cleaned_rid(data->rid, data->replica, csnstr, data->force); /* marks config that we started cleaning a rid */
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
*/
@@ -1506,7 +1555,7 @@ replica_cleanallruv_thread(void *arg)
ruv_obj = replica_get_ruv(data->replica);
ruv = object_get_data (ruv_obj);
while(data->maxcsn && !is_task_aborted(data->rid) && !is_cleaned_rid(data->rid) && !slapi_is_shutting_down()){
- if(csn_get_replicaid(data->maxcsn) == 0 || ruv_covers_csn_cleanallruv(ruv,data->maxcsn)){
+ if(csn_get_replicaid(data->maxcsn) == 0 || ruv_covers_csn_cleanallruv(ruv,data->maxcsn) || strcasecmp(data->force,"yes") == 0){
/* We are caught up, now we can clean the ruv's */
break;
}
@@ -1517,6 +1566,8 @@ replica_cleanallruv_thread(void *arg)
object_release(ruv_obj);
/*
* Next, make sure all the replicas are up and running before sending off the clean ruv tasks
+ *
+ * Even if we are forcing the cleaning, the replicas still need to be up
*/
cleanruv_log(data->task, CLEANALLRUV_ID,"Waiting for all the replicas to be online...");
if(check_agmts_are_alive(data->replica, data->rid, data->task)){
@@ -1528,7 +1579,7 @@ 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(check_agmts_are_caught_up(data->replica, data->rid, csnstr, data->task)){
+ if(strcasecmp(data->force,"no") == 0 && check_agmts_are_caught_up(data, csnstr)){
/* error, aborted or shutdown */
aborted = 1;
goto done;
@@ -1555,10 +1606,11 @@ 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;
+ cleanruv_log(data->task, CLEANALLRUV_ID, "Failed to send task to replica (%s)",agmt_get_long_name(agmt));
break;
}
agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
@@ -1609,10 +1661,11 @@ replica_cleanallruv_thread(void *arg)
found_dirty_rid = 0;
continue;
}
- if(replica_cleanallruv_check_ruv(agmt, rid_text, data->task) == 0){
+ if(replica_cleanallruv_check_ruv(data->repl_root, agmt, rid_text, data->task) == 0){
found_dirty_rid = 0;
} else {
found_dirty_rid = 1;
+ cleanruv_log(data->task, CLEANALLRUV_ID,"Replica is not cleaned yet (%s)",agmt_get_long_name(agmt));
break;
}
agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
@@ -1623,7 +1676,7 @@ replica_cleanallruv_thread(void *arg)
goto done;
}
if(found_dirty_rid == 0){
- break;
+ break;
}
/*
* need to sleep between passes
@@ -1647,9 +1700,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
@@ -1658,29 +1713,189 @@ 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);
- }
- if(data->task){
- slapi_task_finish(data->task, rc);
+ delete_cleaned_rid_config(data);
+ remove_cleaned_rid(data->rid);
}
}
-
+ if(data->task){
+ slapi_task_finish(data->task, rc);
+ }
if(data->payload){
ber_bvfree(data->payload);
}
if(data->repl_obj && free_obj){
object_release(data->repl_obj);
}
+ csn_free(&data->maxcsn);
slapi_sdn_free(&data->sdn);
+ slapi_ch_free_string(&data->repl_root);
+ slapi_ch_free_string(&data->force);
slapi_ch_free_string(&rid_text);
- csn_free(&data->maxcsn);
slapi_ch_free((void **)&data);
}
/*
+ * 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(!agmt_is_enabled(agmt) || 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(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 have 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(cleanruv_data *data, char *maxcsn)
{
Object *agmt_obj;
Repl_Agmt *agmt;
@@ -1688,10 +1903,10 @@ 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", data->rid);
- while(not_all_caughtup && !is_task_aborted(rid) && !slapi_is_shutting_down()){
- agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
+ while(not_all_caughtup && !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_caughtup = 0;
break;
@@ -1699,23 +1914,24 @@ check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_T
while (agmt_obj){
agmt = (Repl_Agmt*)object_get_data (agmt_obj);
if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
- agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
+ agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
not_all_caughtup = 0;
continue;
}
- if(replica_cleanallruv_check_maxcsn(agmt, rid_text, maxcsn, task) == 0){
+ if(replica_cleanallruv_check_maxcsn(agmt, data->repl_root, rid_text, maxcsn, data->task) == 0){
not_all_caughtup = 0;
} else {
not_all_caughtup = 1;
+ cleanruv_log(data->task, CLEANALLRUV_ID, "Replica not caught up (%s)",agmt_get_long_name(agmt));
break;
}
- agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
- } /* agmt while */
+ agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
+ }
- if(not_all_caughtup == 0 || is_task_aborted(rid) ){
+ if(not_all_caughtup == 0 || is_task_aborted(data->rid) ){
break;
}
- cleanruv_log(task, CLEANALLRUV_ID, "Not all replicas caught up, retrying in %d seconds",interval);
+ cleanruv_log(data->task, CLEANALLRUV_ID, "Not all replicas caught up, retrying in %d seconds",interval);
PR_Lock( notify_lock );
PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
PR_Unlock( notify_lock );
@@ -1728,7 +1944,7 @@ check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_T
}
slapi_ch_free_string(&rid_text);
- if(is_task_aborted(rid)){
+ if(is_task_aborted(data->rid)){
return -1;
}
@@ -1763,6 +1979,7 @@ check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task)
not_all_alive = 0;
} else {
not_all_alive = 1;
+ cleanruv_log(task, CLEANALLRUV_ID, "Replica not online (%s)",agmt_get_long_name(agmt));
break;
}
agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
@@ -1793,7 +2010,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;
@@ -1801,10 +2018,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){
@@ -1832,7 +2046,7 @@ 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;
@@ -1859,7 +2073,7 @@ 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";
@@ -1876,7 +2090,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);
}
@@ -1906,6 +2120,23 @@ is_cleaned_rid(ReplicaId rid)
}
int
+is_pre_cleaned_rid(ReplicaId rid)
+{
+ int i;
+
+ slapi_rwlock_rdlock(rid_lock);
+ for(i = 0; i < CLEANRIDSIZ && pre_cleaned_rids[i] != 0; i++){
+ if(rid == pre_cleaned_rids[i]){
+ slapi_rwlock_unlock(rid_lock);
+ return 1;
+ }
+ }
+ slapi_rwlock_unlock(rid_lock);
+
+ return 0;
+}
+
+int
is_task_aborted(ReplicaId rid)
{
int i;
@@ -1924,6 +2155,22 @@ is_task_aborted(ReplicaId rid)
return 0;
}
+static void
+preset_cleaned_rid(ReplicaId rid)
+{
+ int i;
+
+ slapi_rwlock_wrlock(rid_lock);
+ for(i = 0; i < CLEANRIDSIZ; i++){
+ if(pre_cleaned_rids[i] == 0){
+ pre_cleaned_rids[i] = rid;
+ pre_cleaned_rids[i + 1] = 0;
+ break;
+ }
+ }
+ slapi_rwlock_unlock(rid_lock);
+}
+
/*
* Just add the rid to the in memory, as we don't want it to survive after a restart,
* This prevent the changelog from sending updates from this rid, and the local ruv
@@ -1948,7 +2195,7 @@ set_cleaned_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];
@@ -1965,7 +2212,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;
@@ -1977,13 +2224,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);
}
@@ -2036,7 +2281,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);
}
@@ -2047,7 +2292,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;
@@ -2061,117 +2306,126 @@ 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);
- }
- slapi_pblock_destroy (pb);
- slapi_ch_free_string(&dn);
- slapi_ch_free_string(&data);
-}
+ /*
+ * 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);
+ }
/*
* 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);
+
for(i = 0; i < CLEANRIDSIZ && cleaned_rids[i] != rid; i++); /* found rid, stop */
for(; i < CLEANRIDSIZ; i++){
/* rewrite entire array */
cleaned_rids[i] = 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(!agmt_is_enabled(agmt) || 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);
+ /* now do the preset cleaned rids */
+ for(i = 0; i < CLEANRIDSIZ && pre_cleaned_rids[i] != rid; i++); /* found rid, stop */
+ for(; i < CLEANRIDSIZ; i++){
+ /* rewrite entire array */
+ pre_cleaned_rids[i] = pre_cleaned_rids[i + 1];
}
+
+ slapi_rwlock_unlock(rid_lock);
}
/*
@@ -2181,18 +2435,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;
- Slapi_Task *task = NULL;
- Replica *replica;
- ReplicaId rid;
cleanruv_data *data = NULL;
+ PRThread *thread = NULL;
+ Slapi_Task *task = NULL;
Slapi_DN *sdn = NULL;
+ Replica *replica;
+ ReplicaId rid;;
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;
@@ -2216,13 +2469,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
@@ -2236,6 +2482,29 @@ 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;
+ }
+ if(!is_cleaned_rid(rid) && !is_pre_cleaned_rid(rid)){
+ /* we are not cleaning 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;
+ goto out;
+ }
/*
* Get the replica object
*/
@@ -2248,7 +2517,7 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
goto out;
}
/*
- * Check verify value
+ * Check certify value
*/
if(certify_all){
if(strcasecmp(certify_all,"yes") && strcasecmp(certify_all,"no")){
@@ -2260,13 +2529,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");
@@ -2278,8 +2547,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();
/*
@@ -2308,11 +2575,11 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
object_release(r);
cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Unable to create abort thread. Aborting task.");
*returncode = LDAP_OPERATIONS_ERROR;
+ slapi_ch_free_string(&data->certify);
rc = SLAPI_DSE_CALLBACK_ERROR;
}
out:
- csn_free(&maxcsn);
slapi_ch_free_string(&ridstr);
slapi_sdn_free(&sdn);
@@ -2337,6 +2604,8 @@ replica_abort_task_thread(void *arg)
int interval = 10;
int release_it = 0;
+ cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Aborting task for rid(%d)...",data->rid);
+
/*
* Need to build the replica from the dn
*/
@@ -2414,8 +2683,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);
@@ -2437,10 +2710,10 @@ 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;
+ return rc;
}
if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
crc = conn_send_extended_operation(conn, REPL_ABORT_CLEANRUV_OID, payload, NULL, &msgid);
@@ -2462,186 +2735,262 @@ 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;
+ return rc;
}
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);
if (NULL != retsdata)
ber_bvfree(retsdata);
+ slapi_ch_free_string(&retoid);
+ slapi_ch_free_string(&response);
}
- 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(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
+ agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
+ done = 0;
+ 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? */
+ 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 = -1;
+ 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 */
- if(strcmp(ruv_part, maxcsn)){
- /* we are not caught up yet, free, and return */
- ldap_value_free_len(vals);
- ldap_memfree( attr );
- ldap_msgfree( result );
- if(ber){
- ber_free( ber, 0 );
- }
- conn_delete_internal_ext(conn);
- return -1;
- } else {
- /* ok this replica has all the updates from the deleted replica */
- 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 );
- }
- }
- if(result)
- ldap_msgfree( result );
- } else {
- rc = -1;
+ 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 rc;
+ return rc;
}
+
static int
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;
+ return rc;
}
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;
@@ -2655,8 +3004,6 @@ replica_cleanallruv_replica_alive(Repl_Agmt *agmt)
}
if(result)
ldap_msgfree( result );
- } else {
- rc = -1;
}
conn_delete_internal_ext(conn);
@@ -2664,83 +3011,51 @@ 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(char *repl_root, 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){
- return -1;
+ if((conn = conn_new(agmt)) == NULL){
+ return rc;
}
+
+ data = slapi_ch_smprintf("%s:%s",rid_text, repl_root);
+ 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 5aac699..c7c8ab0 100644
--- a/ldap/servers/plugins/replication/repl_extop.c
+++ b/ldap/servers/plugins/replication/repl_extop.c
@@ -1452,7 +1452,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;
@@ -1464,7 +1463,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;
@@ -1473,24 +1472,24 @@ 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 */
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;
@@ -1499,14 +1498,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;
}
@@ -1515,7 +1514,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;
@@ -1529,11 +1528,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();
/*
@@ -1543,7 +1539,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);
@@ -1584,10 +1580,11 @@ 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 *force = NULL;
+ char *extop_oid;
+ char *repl_root;
char *iter;
int release_it = 0;
int rid = 0;
@@ -1605,28 +1602,31 @@ 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));
repl_root = ldap_utf8strtok_r(iter, ":", &iter);
csnstr = ldap_utf8strtok_r(iter, ":", &iter);
+ force = ldap_utf8strtok_r(iter, ":", &iter);
+ if(force == NULL){
+ force = "no";
+ }
maxcsn = csn_new();
csn_init_by_string(maxcsn, csnstr);
/*
* If we already cleaned this server, just return success
*/
- if(is_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;
}
@@ -1635,14 +1635,14 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
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;
}
@@ -1652,10 +1652,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;
}
@@ -1665,15 +1665,19 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
data->task = NULL;
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 */
@@ -1695,18 +1699,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: not ruv caught up maxcsn(%s)\n", csnstr);
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: not ruv caught up 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
*/
@@ -1722,8 +1726,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;
}
@@ -1738,10 +1742,120 @@ 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;
+ }
- ber_int_t response = 1;
+ 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);
- ber_printf(resp_bere, "{e}", response);
+ 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);
+ /*
+ * 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);
+ }
+ /*
+ * 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);
@@ -1761,10 +1875,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 5e8019c..d007f6c 100644
--- a/ldap/servers/plugins/replication/replutil.c
+++ b/ldap/servers/plugins/replication/replutil.c
@@ -765,33 +765,32 @@ repl_set_mtn_state_and_referrals(
ldap_free_urldesc(lud);
}
- if (!referrals_to_set) { /* deleting referrals */
- /* Set state before */
- if (!chain_on_update) {
- slapi_mtn_set_state(repl_root_sdn, (char *)mtn_state);
+ if (!referrals_to_set) { /* deleting referrals */
+ /* Set state before */
+ if (!chain_on_update) {
+ slapi_mtn_set_state(repl_root_sdn, (char *)mtn_state);
+ }
+ /* We should delete referral only if we want to set the
+ replica database in backend state mode */
+ /* if chain on update mode, go ahead and set the referrals anyway */
+ if (strcasecmp(mtn_state, STATE_BACKEND) == 0 || chain_on_update) {
+ rc = slapi_mtn_set_referral(repl_root_sdn, referrals_to_set);
+ if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
+ /* we will get no such attribute (16) if we try to set the referrals to NULL if
+ there are no referrals - not an error */
+ rc = LDAP_SUCCESS;
}
- /* We should delete referral only if we want to set the
- replica database in backend state mode */
- /* if chain on update mode, go ahead and set the referrals anyway */
- if (strcasecmp(mtn_state, STATE_BACKEND) == 0 || chain_on_update) {
- rc = slapi_mtn_set_referral(repl_root_sdn, referrals_to_set);
- if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
- /* we will get no such attribute (16) if we try to set the referrals to NULL if
- there are no referrals - not an error */
- rc = LDAP_SUCCESS;
- }
- }
- } else { /* Replacing */
- rc = slapi_mtn_set_referral(repl_root_sdn, referrals_to_set);
- if (rc == LDAP_SUCCESS && !chain_on_update){
- slapi_mtn_set_state(repl_root_sdn, (char *)mtn_state);
- }
- }
+ }
+ } else { /* Replacing */
+ rc = slapi_mtn_set_referral(repl_root_sdn, referrals_to_set);
+ if (rc == LDAP_SUCCESS && !chain_on_update){
+ slapi_mtn_set_state(repl_root_sdn, (char *)mtn_state);
+ }
+ }
- if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS) {
+ if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS) {
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "repl_set_mtn_referrals: could "
- "not set referrals for replica %s: %d\n",
- slapi_sdn_get_dn(repl_root_sdn), rc);
+ "not set referrals for replica %s: %d\n", slapi_sdn_get_dn(repl_root_sdn), rc);
}
charray_free(referrals_to_set);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index 0db1f87..19f53e5 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,7 +83,7 @@ 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 cfc5e5c..56a8298 100644
--- a/ldap/servers/slapd/back-ldbm/misc.c
+++ b/ldap/servers/slapd/back-ldbm/misc.c
@@ -450,7 +450,7 @@ ldbm_txn_ruv_modify_context( Slapi_PBlock *pb, modify_context *mc )
modify_init( mc, bentry );
- if (modify_apply_mods( mc, smods )) {
+ 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\n",
0, 0, 0 );
rc = -1;
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index 40fa325..7cbaff7 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -353,6 +353,7 @@ void modify_init(modify_context *mc,struct backentry *old_entry);
int modify_apply_mods(modify_context *mc, Slapi_Mods *smods);
int modify_term(modify_context *mc,backend *be);
int modify_switch_entries(modify_context *mc,backend *be);
+int modify_apply_mods_ignore_error(modify_context *mc, Slapi_Mods *smods, int error);
/*
* add.c
diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c
index 85b47a6..5d3e44d 100644
--- a/ldap/servers/slapd/entry.c
+++ b/ldap/servers/slapd/entry.c
@@ -3286,6 +3286,12 @@ 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);
+}
+
+int
+entry_apply_mods_ignore_error( Slapi_Entry *e, LDAPMod **mods, int ignore_error )
+{
int err;
LDAPMod **mp = NULL;
@@ -3295,7 +3301,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 3ee1755..7bd7f3e 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -331,7 +331,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 is_type_protected(const char *type);
-
+int entry_apply_mods_ignore_error( Slapi_Entry *e, LDAPMod **mods, int ignore_error );
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);
/* entrywsi.c */
11 years, 5 months
ldap/servers
by Ludwig Krispenz
ldap/servers/slapd/attrsyntax.c | 16 ++++++++++------
ldap/servers/slapd/libglobs.c | 32 ++++++++++++++++++++++++++++++++
ldap/servers/slapd/proto-slap.h | 1 +
ldap/servers/slapd/schema.c | 9 +++++++++
ldap/servers/slapd/slap.h | 2 ++
5 files changed, 54 insertions(+), 6 deletions(-)
New commits:
commit f102eb72cf8928a585a33423124c2c98a2048bce
Author: Ludwig Krispenz <lkrispen(a)redhat.com>
Date: Mon Nov 19 13:48:23 2012 +0100
Fix for ticket 504
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c
index 59506a0..3c062f1 100644
--- a/ldap/servers/slapd/attrsyntax.c
+++ b/ldap/servers/slapd/attrsyntax.c
@@ -67,11 +67,12 @@ static PLHashTable *internalasi = NULL;
static PLHashTable *name2asi = NULL;
/* read/write lock to protect table */
static Slapi_RWLock *name2asi_lock = NULL;
+static int asi_locking = 1;
-#define AS_LOCK_READ(l) slapi_rwlock_rdlock(l)
-#define AS_LOCK_WRITE(l) slapi_rwlock_wrlock(l)
-#define AS_UNLOCK_READ(l) slapi_rwlock_unlock(l)
-#define AS_UNLOCK_WRITE(l) slapi_rwlock_unlock(l)
+#define AS_LOCK_READ(l) if (asi_locking) { slapi_rwlock_rdlock(l); }
+#define AS_LOCK_WRITE(l) if (asi_locking) { slapi_rwlock_wrlock(l); }
+#define AS_UNLOCK_READ(l) if (asi_locking) { slapi_rwlock_unlock(l); }
+#define AS_UNLOCK_WRITE(l) if (asi_locking) { slapi_rwlock_unlock(l); }
@@ -1043,12 +1044,15 @@ attr_syntax_delete_all()
static int
attr_syntax_init(void)
{
+ int schema_modify_enabled = config_get_schemamod();
+ if (!schema_modify_enabled) asi_locking = 0;
+
if (!oid2asi)
{
oid2asi = PL_NewHashTable(2047, hashNocaseString,
hashNocaseCompare,
PL_CompareValues, 0, 0);
- if ( NULL == ( oid2asi_lock = slapi_new_rwlock())) {
+ if ( asi_locking && NULL == ( oid2asi_lock = slapi_new_rwlock())) {
if(oid2asi) PL_HashTableDestroy(oid2asi);
oid2asi = NULL;
@@ -1063,7 +1067,7 @@ attr_syntax_init(void)
name2asi = PL_NewHashTable(2047, hashNocaseString,
hashNocaseCompare,
PL_CompareValues, 0, 0);
- if ( NULL == ( name2asi_lock = slapi_new_rwlock())) {
+ if ( asi_locking && NULL == ( name2asi_lock = slapi_new_rwlock())) {
if(name2asi) PL_HashTableDestroy(name2asi);
name2asi = NULL;
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index caae9ee..dee7812 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -220,6 +220,7 @@ int init_pw_change;
int init_pw_exp;
int init_pw_syntax;
int init_schemacheck;
+int init_schemamod;
int init_ds4_compatible_schema;
int init_schema_ignore_trailing_spaces;
int init_enquote_sup_oc;
@@ -506,6 +507,10 @@ static struct config_get_and_set {
NULL, 0,
(void**)&global_slapdFrontendConfig.schemacheck,
CONFIG_ON_OFF, NULL, &init_schemacheck},
+ {CONFIG_SCHEMAMOD_ATTRIBUTE, config_set_schemamod,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.schemamod,
+ CONFIG_ON_OFF, NULL, &init_schemamod},
{CONFIG_SYNTAXCHECK_ATTRIBUTE, config_set_syntaxcheck,
NULL, 0,
(void**)&global_slapdFrontendConfig.syntaxcheck,
@@ -1315,6 +1320,7 @@ FrontendConfig_init () {
cfg->timelimit = SLAPD_DEFAULT_TIMELIMIT;
cfg->anon_limits_dn = slapi_ch_strdup("");
init_schemacheck = cfg->schemacheck = LDAP_ON;
+ init_schemamod = cfg->schemamod = LDAP_ON;
init_syntaxcheck = cfg->syntaxcheck = LDAP_OFF;
init_plugin_track = cfg->plugin_track = LDAP_OFF;
init_syntaxlogging = cfg->syntaxlogging = LDAP_OFF;
@@ -3115,6 +3121,20 @@ config_set_schemacheck( const char *attrname, char *value, char *errorbuf, int a
}
int
+config_set_schemamod( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->schemamod),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+int
config_set_syntaxcheck( const char *attrname, char *value, char *errorbuf, int apply ) {
int retVal = LDAP_SUCCESS;
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
@@ -4835,6 +4855,18 @@ config_get_schemacheck() {
}
int
+config_get_schemamod() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->schemamod;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
config_get_syntaxcheck() {
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
int retVal;
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 19c06a2..d206c6d 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -287,6 +287,7 @@ int config_set_accesscontrol( const char *attrname, char *value, char *errorbuf,
int config_set_security( const char *attrname, char *value, char *errorbuf, int apply );
int config_set_readonly( const char *attrname, char *value, char *errorbuf, int apply );
int config_set_schemacheck( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_schemamod( const char *attrname, char *value, char *errorbuf, int apply );
int config_set_syntaxcheck( const char *attrname, char *value, char *errorbuf, int apply );
int config_set_syntaxlogging( const char *attrname, char *value, char *errorbuf, int apply );
int config_set_plugin_tracking( const char *attrname, char *value, char *errorbuf, int apply );
diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c
index c66c320..5eb6520 100644
--- a/ldap/servers/slapd/schema.c
+++ b/ldap/servers/slapd/schema.c
@@ -1648,9 +1648,18 @@ modify_schema_dse (Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *entr
LDAPMod **mods = NULL;
int num_mods = 0; /* count the number of mods */
int schema_ds4x_compat = config_get_ds4_compatible_schema();
+ int schema_modify_enabled = config_get_schemamod();
int reapply_mods = 0;
int is_replicated_operation = 0;
+ if (!schema_modify_enabled) {
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ schema_errprefix_generic, "Generic",
+ "schema update is disabled" );
+ return (SLAPI_DSE_CALLBACK_ERROR);
+ }
+
slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
schema_dse_lock_write();
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index cc99486..8b43f5a 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -1872,6 +1872,7 @@ typedef struct _slapdEntryPoints {
#define CONFIG_OBJECTCLASS_ATTRIBUTE "nsslapd-objectclass"
#define CONFIG_ATTRIBUTE_ATTRIBUTE "nsslapd-attribute"
#define CONFIG_SCHEMACHECK_ATTRIBUTE "nsslapd-schemacheck"
+#define CONFIG_SCHEMAMOD_ATTRIBUTE "nsslapd-schemamod"
#define CONFIG_SYNTAXCHECK_ATTRIBUTE "nsslapd-syntaxcheck"
#define CONFIG_SYNTAXLOGGING_ATTRIBUTE "nsslapd-syntaxlogging"
#define CONFIG_DN_VALIDATE_STRICT_ATTRIBUTE "nsslapd-dn-validate-strict"
@@ -2097,6 +2098,7 @@ typedef struct _slapdFrontendConfig {
int readonly;
int reservedescriptors;
int schemacheck;
+ int schemamod;
int syntaxcheck;
int syntaxlogging;
int dn_validate_strict;
11 years, 5 months
ldap/servers
by Mark Reynolds
ldap/servers/slapd/modify.c | 170 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 161 insertions(+), 9 deletions(-)
New commits:
commit ecf3cc3436accbae478ebe0774e817ead91c6fdf
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Nov 19 15:52:32 2012 -0500
Ticket 394 - modify-delete userpassword
Bug Description: Attempting to delete a specific user password results in an error 16 - if
you are not using clear-text password storage scheme.
Fix Description: The error is caused because it can not find a userpassword attr with
the clear-text password - as its usually encoded. If you know the correct
userpassword encoded value to delete, then you won't get an error 16, but
the unhashed userpassword will not be removed.
This fix checks the scheme of the password value to delete, then compares it
to all the userpassword attrs. Once we find a match, we change the "value to delete"
to the encoded value.
If you do supply an encoded password value to delete, we do the opposite. We
grab all the clear-text unhashed userpasswords from the password entry extension.
Then we compare each one to the hashed value. If we have a match, we know which
unhashed userpassword to delete.
Also, added a check to make sure we don't add encoded values to the unhashed_password
extension.
https://fedorahosted.org/389/ticket/394
Reviewed by: richm (Thank you)
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
index 424badb..867e391 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -80,6 +80,7 @@ static void remove_mod (Slapi_Mods *smods, const char *type, Slapi_Mods *smod_un
#endif
static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old_pw, Slapi_Mods *smods);
static int hash_rootpw (LDAPMod **mods);
+static int valuearray_init_bervalarray_unhashed_only(struct berval **bvals, Slapi_Value ***cvals);
#ifdef LDAP_DEBUG
static const char*
@@ -836,19 +837,137 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
if (strcasecmp (pw_mod->mod_type, SLAPI_USERPWD_ATTR) != 0)
continue;
- if (LDAP_MOD_DELETE == pw_mod->mod_op) {
+ if (SLAPI_IS_MOD_DELETE(pw_mod->mod_op)) {
Slapi_Attr *a = NULL;
- /* delete pseudo password attribute if it exists in the entry */
- if (!slapi_entry_attr_find(e, unhashed_pw_attr, &a)) {
- slapi_mods_add_mod_values(&smods, pw_mod->mod_op,
- unhashed_pw_attr, va);
+ struct pw_scheme *pwsp = NULL;
+ int remove_unhashed_pw = 1;
+ char *password = NULL;
+ char *valpwd = NULL;
+
+ /* if there are mod values, we need to delete a specific userpassword */
+ for ( i = 0; pw_mod->mod_bvalues != NULL && pw_mod->mod_bvalues[i] != NULL; i++ ) {
+ password = slapi_ch_strdup(pw_mod->mod_bvalues[i]->bv_val);
+ pwsp = pw_val2scheme( password, &valpwd, 1 );
+ if(strcmp(pwsp->pws_name, "CLEAR") == 0){
+ /*
+ * CLEAR password
+ *
+ * Ok, so now we to check the entry's userpassword values.
+ * First, find out the password encoding of the entry's pw.
+ * Then compare our clear text password to the encoded userpassword
+ * using the proper scheme. If we have a match, we know which
+ * userpassword value to delete.
+ */
+ Slapi_Attr *pw = NULL;
+ struct berval bval, *bv[2];
+
+ if(slapi_entry_attr_find(e, SLAPI_USERPWD_ATTR, &pw) == 0 && pw){
+ struct pw_scheme *pass_scheme = NULL;
+ Slapi_Value **present_values = NULL;
+ char *pval = NULL;
+ int ii;
+
+ present_values = attr_get_present_values(pw);
+ for(ii = 0; present_values && present_values[ii]; ii++){
+ const char *userpwd = slapi_value_get_string(present_values[ii]);
+
+ pass_scheme = pw_val2scheme( (char *)userpwd, &pval, 1 );
+ if(strcmp(pass_scheme->pws_name,"CLEAR")){
+ /* its encoded, so compare it */
+ if((*(pass_scheme->pws_cmp))( valpwd, pval ) == 0 ){
+ /*
+ * Match, replace the mod value with the encoded password
+ */
+ slapi_ch_free_string(&pw_mod->mod_bvalues[i]->bv_val);
+ pw_mod->mod_bvalues[i]->bv_val = strdup(userpwd);
+ pw_mod->mod_bvalues[i]->bv_len = strlen(userpwd);
+ free_pw_scheme( pass_scheme );
+ break;
+ }
+ } else {
+ /* userpassword is already clear text, nothing to do */
+ free_pw_scheme( pass_scheme );
+ break;
+ }
+ free_pw_scheme( pass_scheme );
+ }
+ }
+ /*
+ * Finally, delete the unhashed userpassword
+ * (this will update the password entry extension)
+ */
+ bval.bv_val = password;
+ bval.bv_len = strlen(password);
+ bv[0] = &bval;
+ bv[1] = NULL;
+ valuearray_init_bervalarray(bv, &va);
+ slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+ valuearray_free(&va);
+ } else {
+ /*
+ * Password is encoded, try and find a matching unhashed_password to delete
+ */
+ Slapi_Value **vals;
+
+ /*
+ * Grab the current unhashed passwords from the password entry extension,
+ * as the "attribute" is no longer present in the entry.
+ */
+ if(slapi_pw_get_entry_ext(e, &vals) == LDAP_SUCCESS){
+ int ii;
+
+ for(ii = 0; vals && vals[ii]; ii++){
+ const char *unhashed_pwd = slapi_value_get_string(vals[ii]);
+ struct pw_scheme *unhashed_pwsp = NULL;
+ struct berval bval, *bv[2];
+
+ /* prepare the value to delete from the list of unhashed userpasswords */
+ bval.bv_val = (char *)unhashed_pwd;
+ bval.bv_len = strlen(unhashed_pwd);
+ bv[0] = &bval;
+ bv[1] = NULL;
+ /*
+ * Compare the clear text unhashed password, to the encoded password
+ * provided by the client.
+ */
+ unhashed_pwsp = pw_val2scheme( (char *)unhashed_pwd, NULL, 1 );
+ if(strcmp(unhashed_pwsp->pws_name, "CLEAR") == 0){
+ if((*(pwsp->pws_cmp))((char *)unhashed_pwd , valpwd) == 0 ){
+ /* match, add the delete mod for this particular unhashed userpassword */
+ valuearray_init_bervalarray(bv, &va);
+ slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+ valuearray_free(&va);
+ free_pw_scheme( unhashed_pwsp );
+ break;
+ }
+ } else {
+ /*
+ * We have a hashed unhashed_userpassword! We must delete it.
+ */
+ valuearray_init_bervalarray(bv, &va);
+ slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+ valuearray_free(&va);
+ }
+ free_pw_scheme( unhashed_pwsp );
+ }
+ } else {
+
+ }
+ }
+ remove_unhashed_pw = 0; /* mark that we already removed the unhashed userpassword */
+ slapi_ch_free_string(&password);
+ free_pw_scheme( pwsp );
+ }
+ if (remove_unhashed_pw && !slapi_entry_attr_find(e, unhashed_pw_attr, &a)){
+ slapi_mods_add_mod_values(&smods, pw_mod->mod_op,unhashed_pw_attr, va);
}
} else {
/* add pseudo password attribute */
- valuearray_init_bervalarray(pw_mod->mod_bvalues, &va);
- slapi_mods_add_mod_values(&smods, pw_mod->mod_op,
- unhashed_pw_attr, va);
- valuearray_free(&va);
+ valuearray_init_bervalarray_unhashed_only(pw_mod->mod_bvalues, &va);
+ if(va){
+ slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+ valuearray_free(&va);
+ }
}
/* Init new value array for hashed value */
@@ -859,6 +978,7 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
/* remove current clear value of userpassword */
ber_bvecfree(pw_mod->mod_bvalues);
+
/* add the cipher in the structure */
valuearray_get_bervalarray(va, &pw_mod->mod_bvalues);
@@ -1020,6 +1140,38 @@ free_and_return:
}
}
+/*
+ * Only add password mods that are in clear text. The console likes to send two mods:
+ * - Already encoded password
+ * - Clear text password
+ *
+ * We don't want to add the encoded value to the unhashed_userpassword attr
+ */
+static int
+valuearray_init_bervalarray_unhashed_only(struct berval **bvals, Slapi_Value ***cvals)
+{
+ int n;
+
+ for(n=0; bvals != NULL && bvals[n] != NULL; n++);
+ if(n==0){
+ *cvals = NULL;
+ } else {
+ struct pw_scheme *pwsp = NULL;
+ int i,p;
+
+ *cvals = (Slapi_Value **) slapi_ch_malloc((n + 1) * sizeof(Slapi_Value *));
+ for(i=0,p=0;i<n;i++){
+ pwsp = pw_val2scheme( bvals[i]->bv_val, NULL, 1 );
+ if(strcmp(pwsp->pws_name, "CLEAR") == 0){
+ (*cvals)[p++] = slapi_value_new_berval(bvals[i]);
+ }
+ free_pw_scheme( pwsp );
+ }
+ (*cvals)[p] = NULL;
+ }
+ return n;
+}
+
#if 0 /* not used */
static void remove_mod (Slapi_Mods *smods, const char *type, Slapi_Mods *smod_unhashed)
{
11 years, 5 months
ldap/servers
by Richard Allen Megginson
ldap/servers/plugins/rootdn_access/rootdn_access.c | 1 +
ldap/servers/slapd/back-ldbm/dblayer.c | 2 +-
ldap/servers/slapd/util.c | 6 +++++-
3 files changed, 7 insertions(+), 2 deletions(-)
New commits:
commit 32ab01f55684859213bfebf8190b82ba84f374c5
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Thu Oct 25 17:16:08 2012 -0600
minor fixes for bdb 4.2/4.3 and mozldap
diff --git a/ldap/servers/plugins/rootdn_access/rootdn_access.c b/ldap/servers/plugins/rootdn_access/rootdn_access.c
index ad1e125..5323915 100644
--- a/ldap/servers/plugins/rootdn_access/rootdn_access.c
+++ b/ldap/servers/plugins/rootdn_access/rootdn_access.c
@@ -46,6 +46,7 @@
#include <nspr.h>
#include <time.h>
#include <ctype.h>
+#include <string.h>
/*
* Add an entry like the following to dse.ldif to enable this plugin:
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c
index 26007f4..5e53de9 100644
--- a/ldap/servers/slapd/back-ldbm/dblayer.c
+++ b/ldap/servers/slapd/back-ldbm/dblayer.c
@@ -136,7 +136,7 @@
#define LOG_FLUSH(env, lsn) (env)->log_flush((env), (lsn))
#define LOCK_DETECT(env, flags, atype, aborted) \
(env)->lock_detect((env), (flags), (atype), (aborted))
-#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4000 /* db4.4 or later */
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4400 /* db4.4 or later */
#define DB_ENV_SET_TAS_SPINS(env, tas_spins) \
(env)->mutex_set_tas_spins((env), (tas_spins))
#else /* < 4.4 */
diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c
index a70910f..bdff366 100644
--- a/ldap/servers/slapd/util.c
+++ b/ldap/servers/slapd/util.c
@@ -340,12 +340,16 @@ filter_stuff_func(void *arg, const char *val, PRUint32 slen)
buf = escaped_filter.bv_val;
}
#else
+ char *val2 = NULL;
buf = slapi_ch_calloc(sizeof(char), filter_len*3 + 1);
- if(do_escape_string(val, filter_len, buf, special_filter) == NULL){
+ val2 = do_escape_string(val, filter_len, buf, special_filter);
+ if(val2 == NULL){
LDAPDebug(LDAP_DEBUG_TRACE, "slapi_filter_sprintf: failed to escape filter value(%s)\n",val,0,0);
ctx->next_arg_needs_esc_norm = 0;
slapi_ch_free_string(&buf);
return -1;
+ } else if (val == val2) { /* value did not need escaping and was just returned */
+ strcpy(buf, val); /* just use value as-is - len did not change */
} else {
filter_len = strlen(buf);
}
11 years, 5 months
ldap/servers
by Noriko Hosoi
ldap/servers/slapd/connection.c | 90 ++++++++++++++++++++++++++--------------
1 file changed, 59 insertions(+), 31 deletions(-)
New commits:
commit 48b35ec4e48a38c257d5b9a5d2ef584661895261
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Sun Oct 14 16:46:16 2012 -0700
Trac Ticket #276 - Multiple threads simultaneously working on
connection's private buffer causes ns-slapd to abort
https://fedorahosted.org/389/ticket/276
Bug description: When a connection is to be released, the current
code releases the connection object before making it readable,
which leaves a small window for multiple threads accessing the
same private buffer.
Fix description: This patch moves the location of releasing the
connection object after the connection is readable.
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
index a3b1df5..d598b0b 100644
--- a/ldap/servers/slapd/connection.c
+++ b/ldap/servers/slapd/connection.c
@@ -2029,6 +2029,11 @@ void connection_make_readable(Connection *conn)
signal_listner();
}
+void connection_make_readable_nolock(Connection *conn)
+{
+ conn->c_gettingber = 0;
+}
+
/*
* Figure out the operation completion rate for this connection
*/
@@ -2166,7 +2171,8 @@ connection_threadmain()
Connection *conn = NULL;
Operation *op;
ber_tag_t tag = 0;
- int need_wakeup;
+ int need_wakeup = 0;
+ int need_conn_release = 0;
int thread_turbo_flag = 0;
int ret = 0;
int more_data = 0;
@@ -2303,7 +2309,7 @@ connection_threadmain()
* they are received off the wire.
*/
replication_connection = conn->c_isreplication_session;
- if (tag != LDAP_REQ_UNBIND && (!thread_turbo_flag) && !more_data && !replication_connection) {
+ if ((tag != LDAP_REQ_UNBIND) && !thread_turbo_flag && !more_data && !replication_connection) {
connection_make_readable(conn);
}
@@ -2350,53 +2356,75 @@ done:
/* total number of ops for the server */
slapi_counter_increment(ops_completed);
/* If this op isn't a persistent search, remove it */
+ need_conn_release = 0;
if ( !( pb->pb_op->o_flags & OP_FLAG_PS )) {
/* delete from connection operation queue & decr refcnt */
PR_Lock( conn->c_mutex );
connection_remove_operation( conn, op );
- /* destroying the pblock will cause destruction of the operation
- * so this must happend before releasing the connection
- */
+ /* destroying the pblock will cause destruction of the operation
+ * so this must happend before releasing the connection
+ */
slapi_pblock_destroy( pb );
- /* If we're in turbo mode, we keep our reference to the connection
- alive */
+ /* If we're in turbo mode, we keep our reference to the connection
+ alive */
if (!thread_turbo_flag && !more_data) {
- connection_release_nolock (conn);
- }
+ /*
+ * Don't release the connection now.
+ * But note down what to do.
+ */
+ need_conn_release = 1;
+ }
PR_Unlock( conn->c_mutex );
} else { /* the ps code acquires a ref to the conn - we need to release ours here */
PR_Lock( conn->c_mutex );
- connection_release_nolock (conn);
+ connection_release_nolock (conn);
PR_Unlock( conn->c_mutex );
}
- /* Since we didn't do so earlier, we need to make a replication connection readable again here */
- if ( ((1 == is_timedout) || (replication_connection && !thread_turbo_flag)) && !more_data)
- connection_make_readable(conn);
pb = NULL;
if (doshutdown) {
+ PR_Lock(conn->c_mutex);
+ connection_make_readable_nolock(conn);
+ conn->c_threadnumber--;
+ connection_release_nolock(conn);
+ PR_Unlock(conn->c_mutex);
+ signal_listner();
return;
}
- if (!thread_turbo_flag && !more_data) { /* Don't do this in turbo mode */
- PR_Lock( conn->c_mutex );
- /* if the threadnumber of now below the maximum, wakeup
- * the listener thread so that we start polling on this
- * connection again
- */
- /* DBDB I think this code is bogus -- we already signaled the listener above here */
- if (conn->c_threadnumber == config_get_maxthreadsperconn())
- need_wakeup = 1;
- else
- need_wakeup = 0;
- conn->c_threadnumber--;
- PR_Unlock( conn->c_mutex );
-
- if (need_wakeup)
- signal_listner();
+ if (!more_data) { /* no more data in the buffer */
+ if (!thread_turbo_flag) { /* Don't do this in turbo mode */
+ /* Since we didn't do so earlier, we need to make a
+ * replication connection readable again here */
+ PR_Lock( conn->c_mutex );
+ if (replication_connection || (1 == is_timedout)) {
+ connection_make_readable_nolock(conn);
+ need_wakeup = 1;
+ }
+ /* if the threadnumber of now below the maximum, wakeup
+ * the listener thread so that we start polling on this
+ * connection again
+ */
+ if (!need_wakeup) {
+ if (conn->c_threadnumber == config_get_maxthreadsperconn())
+ need_wakeup = 1;
+ else
+ need_wakeup = 0;
+ }
+ conn->c_threadnumber--;
+ if (need_conn_release) {
+ connection_release_nolock(conn);
+ }
+ PR_Unlock( conn->c_mutex );
+ /* Call signal_listner after releasing the
+ * connection if required. */
+ if (need_wakeup) {
+ signal_listner();
+ }
+ } else if (1 == is_timedout) {
+ connection_make_readable(conn);
+ }
}
-
-
} /* while (1) */
}
11 years, 5 months
ldap/servers
by Ludwig Krispenz
ldap/servers/slapd/back-ldbm/monitor.c | 2 ++
1 file changed, 2 insertions(+)
New commits:
commit 2f1021c8253ffe8c21e2a1e1a10a7953bda64948
Author: Ludwig Krispenz <lkrispen(a)redhat.com>
Date: Fri Nov 16 16:58:35 2012 +0100
Fix for ticket 465: cn=monitor showing stats for other db instances
Check that part of the db file name that matches is the full db dir name
diff --git a/ldap/servers/slapd/back-ldbm/monitor.c b/ldap/servers/slapd/back-ldbm/monitor.c
index ee4f01a..1a06a25 100644
--- a/ldap/servers/slapd/back-ldbm/monitor.c
+++ b/ldap/servers/slapd/back-ldbm/monitor.c
@@ -196,6 +196,8 @@ int ldbm_back_monitor_instance_search(Slapi_PBlock *pb, Slapi_Entry *e,
if (strncmp(mpfstat[i]->file_name, inst->inst_dir_name,
strlen(inst->inst_dir_name)) != 0)
continue;
+ if (mpfstat[i]->file_name[strlen(inst->inst_dir_name)] != get_sep(mpfstat[i]->file_name))
+ continue;
/* Since the filenames are now relative, we need to construct an absolute version
* for the purpose of stat() etc below...
11 years, 5 months
Branch '389-ds-base-1.2.11' - ldap/servers
by Mark Reynolds
ldap/servers/plugins/dna/dna.c | 4 ++
ldap/servers/slapd/add.c | 56 +++++++++++++++++++++++++++++++++----
ldap/servers/slapd/opshared.c | 8 +++--
ldap/servers/slapd/proto-slap.h | 1
ldap/servers/slapd/slapi-private.h | 10 ++++++
5 files changed, 71 insertions(+), 8 deletions(-)
New commits:
commit fb8c9f305398f713154bc3d8dddeb89d3c9d386a
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Fri Oct 19 10:22:21 2012 -0400
Ticket 495 - internalModifiersname not updated by DNA plugin
Bug Description: If you are using the "nsslapd-plugin-binddn-tracking", and the DNA plugin
modifiers the entry, the internalmodifiersname is not updated.
Fix Description: This is because the DNA plugin directly modifies the entry, and does not
use the internal modify functions that would trigger the last mod attributes
to be updated. So we have to call the last mod update funtciont directly from
the dna plugin.
There is also a slight change to the behavior now. The internalModifiersname &
internalCreatorsname will never be the bind dn, but instead it will be the plugin
that actually did the update. So if a entry was not touched by a DS plugin, then
the "database" plugin would be the internal modifier/creator:
cn=ldbm database,cn=plugins,cn=config
This would also allow us to detect if someone replaced the default backend.
https://fedorahosted.org/389/ticket/495
Reviewed by: nhosoi(Thanks!)
diff --git a/ldap/servers/plugins/dna/dna.c b/ldap/servers/plugins/dna/dna.c
index ef01735..66d4a05 100644
--- a/ldap/servers/plugins/dna/dna.c
+++ b/ldap/servers/plugins/dna/dna.c
@@ -2846,6 +2846,8 @@ _dna_pre_op_add(Slapi_PBlock *pb, Slapi_Entry *e)
/* no need to dup */
DNA_NEEDS_UPDATE);
}
+ /* Update the internalModifiersname for this add op */
+ add_internal_modifiersname(pb, e);
/* Make sure we don't generate for this
* type again by keeping a list of types
@@ -3101,6 +3103,8 @@ _dna_pre_op_modify(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Mods *smods)
/* no need to dup */
DNA_NEEDS_UPDATE);
}
+ /* Update the internalModifersname for this mod op */
+ modify_update_last_modified_attr(pb, smods);
/* Make sure we don't generate for this
* type again by keeping a list of types
diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c
index 55deeee..3206d5b 100644
--- a/ldap/servers/slapd/add.c
+++ b/ldap/servers/slapd/add.c
@@ -73,7 +73,7 @@
/* Forward declarations */
static int add_internal_pb (Slapi_PBlock *pb);
static void op_shared_add (Slapi_PBlock *pb);
-static int add_created_attrs(Operation *op, Slapi_Entry *e);
+static int add_created_attrs(Slapi_PBlock *pb, Slapi_Entry *e);
static int check_rdn_for_created_attrs(Slapi_Entry *e);
static void handle_fast_add(Slapi_PBlock *pb, Slapi_Entry *entry);
static int add_uniqueid (Slapi_Entry *e);
@@ -631,7 +631,7 @@ static void op_shared_add (Slapi_PBlock *pb)
/* can get lastmod only after backend is selected */
slapi_pblock_get(pb, SLAPI_BE_LASTMOD, &lastmod);
- if (lastmod && add_created_attrs(operation, e) != 0)
+ if (lastmod && add_created_attrs(pb, e) != 0)
{
send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
"cannot insert computed attributes", 0, NULL);
@@ -745,20 +745,25 @@ done:
}
static int
-add_created_attrs(Operation *op, Slapi_Entry *e)
+add_created_attrs(Slapi_PBlock *pb, Slapi_Entry *e)
{
char buf[20];
char *binddn = NULL;
+ char *plugin_dn = NULL;
struct berval bv;
struct berval *bvals[2];
time_t curtime;
struct tm ltm;
+ Operation *op;
+ struct slapdplugin *plugin = NULL;
+ struct slapi_componentid *cid = NULL;
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
LDAPDebug(LDAP_DEBUG_TRACE, "add_created_attrs\n", 0, 0, 0);
bvals[0] = &bv;
bvals[1] = NULL;
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
if(slapdFrontendConfig->plugin_track){
/* plugin bindDN tracking is enabled, grab the dn from thread local storage */
@@ -766,8 +771,21 @@ add_created_attrs(Operation *op, Slapi_Entry *e)
bv.bv_val = "";
bv.bv_len = strlen(bv.bv_val);
} else {
- bv.bv_val = (char*)slapi_sdn_get_dn(&op->o_sdn);
- bv.bv_len = strlen(bv.bv_val);
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &cid);
+ if (cid){
+ plugin=(struct slapdplugin *) cid->sci_plugin;
+ } else {
+ slapi_pblock_get (pb, SLAPI_PLUGIN, &plugin);
+ }
+ if(plugin)
+ plugin_dn = plugin_get_dn (plugin);
+ if(plugin_dn){
+ bv.bv_val = plugin_dn;
+ bv.bv_len = strlen(bv.bv_val);
+ } else {
+ bv.bv_val = (char*)slapi_sdn_get_dn(&op->o_sdn);
+ bv.bv_len = strlen(bv.bv_val);
+ }
}
slapi_entry_attr_replace(e, "internalCreatorsName", bvals);
slapi_entry_attr_replace(e, "internalModifiersName", bvals);
@@ -971,3 +989,31 @@ check_oc_subentry(Slapi_Entry *e, struct berval **vals, char *normtype) {
}
return subentry;
}
+
+/*
+ * Used by plugins that modify entries on add operations, otherwise the internalModifiersname
+ * would be incorrect.
+ */
+void
+add_internal_modifiersname(Slapi_PBlock *pb, Slapi_Entry *e)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ struct slapi_componentid *cid = NULL;
+ struct slapdplugin *plugin = NULL;
+ char *plugin_dn = NULL;
+
+ if(slapdFrontendConfig->plugin_track){
+ /* plugin bindDN tracking is enabled, grab the bind dn from thread local storage */
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &cid);
+ if (cid){
+ plugin=(struct slapdplugin *) cid->sci_plugin;
+ } else {
+ slapi_pblock_get (pb, SLAPI_PLUGIN, &plugin);
+ }
+ if(plugin)
+ plugin_dn = plugin_get_dn (plugin);
+ if(plugin_dn){
+ slapi_entry_attr_set_charptr(e, "internalModifiersname", plugin_dn);
+ }
+ }
+}
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
index 2701250..485763e 100644
--- a/ldap/servers/slapd/opshared.c
+++ b/ldap/servers/slapd/opshared.c
@@ -133,7 +133,8 @@ do_ps_service(Slapi_Entry *e, Slapi_Entry *eprev, ber_int_t chgtype, ber_int_t c
(ps_service_fn)(e, eprev, chgtype, chgnum);
}
-void modify_update_last_modified_attr(Slapi_PBlock *pb, Slapi_Mods *smods)
+void
+modify_update_last_modified_attr(Slapi_PBlock *pb, Slapi_Mods *smods)
{
char buf[20];
char *plugin_dn = NULL;
@@ -160,8 +161,11 @@ void modify_update_last_modified_attr(Slapi_PBlock *pb, Slapi_Mods *smods)
bv.bv_len = strlen(bv.bv_val);
} else {
slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &cid);
- if (cid)
+ if (cid){
plugin=(struct slapdplugin *) cid->sci_plugin;
+ } else {
+ slapi_pblock_get (pb, SLAPI_PLUGIN, &plugin);
+ }
if(plugin)
plugin_dn = plugin_get_dn (plugin);
if(plugin_dn){
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 7e438b7..2289efa 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -1284,7 +1284,6 @@ void set_config_params (Slapi_PBlock *pb);
/* set parameters common for all internal operations */
void set_common_params (Slapi_PBlock *pb);
void do_ps_service(Slapi_Entry *e, Slapi_Entry *eprev, ber_int_t chgtype, ber_int_t chgnum);
-void modify_update_last_modified_attr(Slapi_PBlock *pb, Slapi_Mods *smods);
/*
* debugdump.cpp
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
index f995e30..f7b4d04 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -1247,6 +1247,16 @@ int is_slapd_running();
/* attrsyntax.c */
int slapi_add_internal_attr_syntax( const char *name, const char *oid, const char *syntax, const char *mr_equality, unsigned long extraflags );
+/* pw.c */
+void pw_exp_init ( void );
+int pw_copy_entry_ext(Slapi_Entry *src_e, Slapi_Entry *dest_e);
+
+/* op_shared.c */
+void modify_update_last_modified_attr(Slapi_PBlock *pb, Slapi_Mods *smods);
+
+/* add.c */
+void add_internal_modifiersname(Slapi_PBlock *pb, Slapi_Entry *e);
+
#ifdef __cplusplus
}
#endif
11 years, 5 months
ldap/servers
by Mark Reynolds
ldap/servers/slapd/daemon.c | 8 ++++----
ldap/servers/slapd/libglobs.c | 14 ++++++++++----
ldap/servers/slapd/slap.h | 16 ++++++++++++++--
3 files changed, 28 insertions(+), 10 deletions(-)
New commits:
commit e53973451dc8dbdd9e8829a1d86a2cd7a14733fe
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Thu Nov 15 12:57:35 2012 -0500
Ticket 507 - use mutex for FrontendConfig lock instead of rwlock
Bug Description: There was a lot of contention over the read/write lock
for the frontend config
Fix Description: Updated the macros to use a simple lock.
https://fedorahosted.org/389/ticket/507
Reviewed by: noriko(Thanks!)
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 62a52fc..85052fe 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -602,11 +602,11 @@ disk_mon_get_dirs(char ***list, int logs_critical){
char *dir = NULL;
if(logs_critical){
- slapi_rwlock_rdlock(config->cfg_rwlock);
+ CFG_LOCK_READ(config);
disk_mon_add_dir(list, config->accesslog);
disk_mon_add_dir(list, config->errorlog);
disk_mon_add_dir(list, config->auditlog);
- slapi_rwlock_unlock(config->cfg_rwlock);
+ CFG_UNLOCK_READ(config);
}
/* Add /var just to be safe */
@@ -617,9 +617,9 @@ disk_mon_get_dirs(char ***list, int logs_critical){
#endif
/* config and backend directories */
- slapi_rwlock_rdlock(config->cfg_rwlock);
+ CFG_LOCK_READ(config);
disk_mon_add_dir(list, config->configdir);
- slapi_rwlock_unlock(config->cfg_rwlock);
+ CFG_UNLOCK_READ(config);
be = slapi_get_first_backend (&cookie);
while (be) {
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index b19c2d9..caae9ee 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -1238,14 +1238,20 @@ void
FrontendConfig_init () {
slapdFrontendConfig_t *cfg = getFrontendConfig();
+#if SLAPI_CFG_USE_RWLOCK == 1
/* initialize the read/write configuration lock */
if ( (cfg->cfg_rwlock = slapi_new_rwlock()) == NULL ) {
- LDAPDebug ( LDAP_DEBUG_ANY,
- "FrontendConfig_init: failed to initialize cfg_rwlock. Exiting now.",
- 0,0,0 );
+ LDAPDebug ( LDAP_DEBUG_ANY, "FrontendConfig_init: "
+ "failed to initialize cfg_rwlock. Exiting now.",0,0,0);
exit(-1);
}
-
+#else
+ if ((cfg->cfg_lock = PR_NewLock()) == NULL){
+ LDAPDebug(LDAP_DEBUG_ANY, "FrontendConfig_init: "
+ "failed to initialize cfg_lock. Exiting now.",0,0,0);
+ exit(-1);
+ }
+#endif
cfg->port = LDAP_PORT;
cfg->secureport = LDAPS_PORT;
cfg->ldapi_filename = slapi_ch_strdup(SLAPD_LDAPI_DEFAULT_FILENAME);
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index dbd9727..cc99486 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -2056,10 +2056,18 @@ typedef struct _slapdEntryPoints {
/* flag used to indicate that the change to the config parameter should be saved */
#define CONFIG_APPLY 1
-#define CFG_LOCK_READ(cfg) slapi_rwlock_rdlock(cfg->cfg_rwlock)
-#define CFG_UNLOCK_READ(cfg) slapi_rwlock_unlock(cfg->cfg_rwlock)
+#define SLAPI_CFG_USE_RWLOCK 0
+#if SLAPI_CFG_USE_RWLOCK == 0
+#define CFG_LOCK_READ(cfg) PR_Lock(cfg->cfg_lock)
+#define CFG_UNLOCK_READ(cfg) PR_Unlock(cfg->cfg_lock)
+#define CFG_LOCK_WRITE(cfg) PR_Lock(cfg->cfg_lock)
+#define CFG_UNLOCK_WRITE(cfg) PR_Unlock(cfg->cfg_lock)
+#else
+#define CFG_LOCK_READ(cfg) slapi_rwlock_rdlock(cfg->cfg_rwlock)
+#define CFG_UNLOCK_READ(cfg) slapi_rwlock_unlock(cfg->cfg_rwlock)
#define CFG_LOCK_WRITE(cfg) slapi_rwlock_wrlock(cfg->cfg_rwlock)
#define CFG_UNLOCK_WRITE(cfg) slapi_rwlock_unlock(cfg->cfg_rwlock)
+#endif
#define REFER_MODE_OFF 0
#define REFER_MODE_ON 1
@@ -2067,7 +2075,11 @@ typedef struct _slapdEntryPoints {
#define MAX_ALLOWED_TIME_IN_SECS 2147483647
typedef struct _slapdFrontendConfig {
+#if SLAPI_CFG_USE_RWLOCK == 1
Slapi_RWLock *cfg_rwlock; /* read/write lock to serialize access */
+#else
+ PRLock *cfg_lock;
+#endif
struct pw_scheme *rootpwstoragescheme;
int accesscontrol;
int groupevalnestlevel;
11 years, 5 months
ldap/servers
by Ludwig Krispenz
ldap/servers/slapd/attrsyntax.c | 18 ++++++++++++++++++
ldap/servers/slapd/dn.c | 15 +++------------
ldap/servers/slapd/slapi-plugin.h | 1 +
3 files changed, 22 insertions(+), 12 deletions(-)
New commits:
commit 49b7b668953f576040f308081e1920a325f49971
Author: Ludwig Krispenz <lkrispen(a)redhat.com>
Date: Fri Nov 16 14:13:27 2012 +0100
Fix for ticket 510
Avoid creating an attribute just to determine the syntax for a type, look up the syntax directly by type
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c
index f134fa4..59506a0 100644
--- a/ldap/servers/slapd/attrsyntax.c
+++ b/ldap/servers/slapd/attrsyntax.c
@@ -812,6 +812,24 @@ slapi_attr_is_dn_syntax_attr(Slapi_Attr *attr)
return dn_syntax;
}
+int
+slapi_attr_is_dn_syntax_type(char *type)
+{
+ const char *syntaxoid = NULL;
+ int dn_syntax = 0; /* not DN, by default */
+ struct asyntaxinfo * asi;
+
+ asi = attr_syntax_get_by_name(type);
+
+ if (asi && asi->asi_plugin) { /* If not set, there is no way to get the info */
+ if (syntaxoid = asi->asi_plugin->plg_syntax_oid) {
+ dn_syntax = ((0 == strcmp(syntaxoid, NAMEANDOPTIONALUID_SYNTAX_OID))
+ || (0 == strcmp(syntaxoid, DN_SYNTAX_OID)));
+ }
+ }
+ return dn_syntax;
+}
+
#ifdef ATTR_LDAP_DEBUG
PRIntn
diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
index 0ca44e7..d643d33 100644
--- a/ldap/servers/slapd/dn.c
+++ b/ldap/servers/slapd/dn.c
@@ -608,7 +608,6 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
/* See if the type is defined to use
* the Distinguished Name syntax. */
char savechar;
- Slapi_Attr test_attr;
/* We need typestart to be a string containing only
* the type. We terminate the type and then reset
@@ -616,9 +615,7 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
savechar = *d;
*d = '\0';
- slapi_attr_init(&test_attr, typestart);
- is_dn_syntax = slapi_attr_is_dn_syntax_attr(&test_attr);
- attr_done(&test_attr);
+ is_dn_syntax = slapi_attr_is_dn_syntax_type(typestart);
/* Reset the character we modified. */
*d = savechar;
@@ -629,7 +626,6 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
/* See if the type is defined to use
* the Distinguished Name syntax. */
char savechar;
- Slapi_Attr test_attr;
/* We need typestart to be a string containing only
* the type. We terminate the type and then reset
@@ -637,9 +633,7 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
savechar = *d;
*d = '\0';
- slapi_attr_init(&test_attr, typestart);
- is_dn_syntax = slapi_attr_is_dn_syntax_attr(&test_attr);
- attr_done(&test_attr);
+ is_dn_syntax = slapi_attr_is_dn_syntax_type(typestart);
/* Reset the character we modified. */
*d = savechar;
@@ -650,7 +644,6 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
/* See if the type is defined to use
* the Distinguished Name syntax. */
char savechar;
- Slapi_Attr test_attr;
/* We need typestart to be a string containing only
* the type. We terminate the type and then reset
@@ -658,9 +651,7 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
savechar = *d;
*d = '\0';
- slapi_attr_init(&test_attr, typestart);
- is_dn_syntax = slapi_attr_is_dn_syntax_attr(&test_attr);
- attr_done(&test_attr);
+ is_dn_syntax = slapi_attr_is_dn_syntax_type(typestart);
/* Reset the character we modified. */
*d = savechar;
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 4883ad5..978b02c 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -3738,6 +3738,7 @@ int slapi_attr_get_syntax_oid_copy( const Slapi_Attr *a, char **oidp );
* \return \c 0 if the attribute does not use a DN syntax.
*/
int slapi_attr_is_dn_syntax_attr(Slapi_Attr *attr);
+int slapi_attr_is_dn_syntax_type(char *type);
/**
* Get the flags associated with a particular attribute.
11 years, 5 months