|
|
@@ -71,6 +71,7 @@
|
|
|
*
|
|
|
*/
|
|
|
static int check_replica_id_uniqueness(Replica *replica, RUV *supplier_ruv);
|
|
|
+static multimaster_mtnode_extension *replica_config_get_mtnode_by_dn(const char *dn);
|
|
|
|
|
|
static int
|
|
|
encode_ruv (BerElement *ber, const RUV *ruv)
|
|
|
@@ -1260,7 +1261,6 @@ multimaster_extop_EndNSDS50ReplicationRequest(Slapi_PBlock *pb)
|
|
|
{
|
|
|
/* The ruv from the supplier may have changed. Report the change on the
|
|
|
consumer side */
|
|
|
-
|
|
|
replica_update_ruv_consumer(r, connext->supplier_ruv);
|
|
|
}
|
|
|
|
|
|
@@ -1314,6 +1314,345 @@ free_and_return:
|
|
|
return return_value;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Return the mtnode extension of the dn
|
|
|
+ */
|
|
|
+static multimaster_mtnode_extension *
|
|
|
+replica_config_get_mtnode_by_dn(const char *dn)
|
|
|
+{
|
|
|
+ Slapi_DN *sdn;
|
|
|
+ mapping_tree_node *mtnode;
|
|
|
+ multimaster_mtnode_extension *ext = NULL;
|
|
|
+
|
|
|
+ sdn = slapi_sdn_new_dn_byval(dn);
|
|
|
+ mtnode = slapi_get_mapping_tree_node_by_dn (sdn);
|
|
|
+ if (mtnode) {
|
|
|
+ /* check if the replica object already exists in the subtree */
|
|
|
+ ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);
|
|
|
+ }
|
|
|
+ slapi_sdn_free (&sdn);
|
|
|
+
|
|
|
+ return ext;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Decode the ber element passed to us by the cleanAllRUV task
|
|
|
+ */
|
|
|
+static int
|
|
|
+decode_cleanruv_payload(struct berval *extop_value, char **payload)
|
|
|
+{
|
|
|
+ BerElement *tmp_bere = NULL;
|
|
|
+ int rc = 0;
|
|
|
+
|
|
|
+ if ((tmp_bere = ber_init(extop_value)) == NULL){
|
|
|
+ rc = -1;
|
|
|
+ goto free_and_return;
|
|
|
+ }
|
|
|
+ if (ber_scanf(tmp_bere, "{") == LBER_ERROR){
|
|
|
+ rc = -1;
|
|
|
+ goto free_and_return;
|
|
|
+ }
|
|
|
+ if (ber_get_stringa(tmp_bere, payload) == LBER_DEFAULT){
|
|
|
+ rc = -1;
|
|
|
+ goto free_and_return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ber_scanf(tmp_bere, "}") == LBER_ERROR){
|
|
|
+ rc = -1;
|
|
|
+ goto free_and_return;
|
|
|
+ }
|
|
|
+
|
|
|
+free_and_return:
|
|
|
+ if (-1 == rc){
|
|
|
+ slapi_ch_free_string(payload);
|
|
|
+ }
|
|
|
+ if (NULL != tmp_bere){
|
|
|
+ ber_free(tmp_bere, 1);
|
|
|
+ tmp_bere = NULL;
|
|
|
+ }
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Process the REPL_CLEANRUV_OID extended operation.
|
|
|
+ *
|
|
|
+ * The payload consists of the replica ID, and the repl root dn. Since this is
|
|
|
+ * basically a replication operation, it could of originated here and bounced
|
|
|
+ * back from another master. So check the rid against the "cleaned_rid". If
|
|
|
+ * it's a match, then we were already here, and we can just return success.
|
|
|
+ *
|
|
|
+ * Otherwise, we the set the cleaned_rid from the payload, fire off extended ops
|
|
|
+ * to all the replica agreements on this replica. Then perform the actual
|
|
|
+ * cleanruv_task on this replica.
|
|
|
+ */
|
|
|
+int
|
|
|
+multimaster_extop_cleanruv(Slapi_PBlock *pb){
|
|
|
+ multimaster_mtnode_extension *mtnode_ext;
|
|
|
+ Repl_Connection *conn;
|
|
|
+ const Slapi_DN *dn;
|
|
|
+ Replica *r = NULL;
|
|
|
+ Object *agmt_obj;
|
|
|
+ Repl_Agmt *agmt;
|
|
|
+ ConnResult crc;
|
|
|
+ struct berval *extop_value;
|
|
|
+ char *extop_oid;
|
|
|
+ char *repl_root;
|
|
|
+ char *payload = NULL;
|
|
|
+ char *iter;
|
|
|
+ int send_msgid = 0;
|
|
|
+ int rid = 0;
|
|
|
+ int rc = 0;
|
|
|
+
|
|
|
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
|
|
|
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
|
|
|
+
|
|
|
+ if (NULL == extop_oid || strcmp(extop_oid, REPL_CLEANRUV_OID) != 0 ||
|
|
|
+ NULL == extop_value || NULL == extop_value->bv_val){
|
|
|
+ /* something is wrong, error out */
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Extract the rid and repl_root from the payload
|
|
|
+ */
|
|
|
+ if(decode_cleanruv_payload(extop_value, &payload)){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_extop: failed to decode payload. Aborting ext op\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
|
|
|
+ repl_root = ldap_utf8strtok_r(iter, ":", &iter);
|
|
|
+
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanruv_extop: cleaning rid (%d)...\n",rid);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we already cleaned this server, just return success
|
|
|
+ */
|
|
|
+ if(is_cleaned_rid(rid)){
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanruv_extop: rid (%d) has already been cleaned, skipping\n",rid);
|
|
|
+ return rc;
|
|
|
+ } else {
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanruv_extop: cleaning 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, "cleanruv_extop: failed to get replication node "
|
|
|
+ "from (%s), aborting operation\n", repl_root);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (mtnode_ext->replica)
|
|
|
+ object_acquire (mtnode_ext->replica);
|
|
|
+ if (mtnode_ext->replica == NULL){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_extop: replica is missing from (%s), "
|
|
|
+ "aborting operation\n",repl_root);
|
|
|
+ rc = LDAP_OPERATIONS_ERROR;
|
|
|
+ goto free_and_return;
|
|
|
+ }
|
|
|
+ r = (Replica*)object_get_data (mtnode_ext->replica);
|
|
|
+ /*
|
|
|
+ * Send out extended ops to each repl agreement
|
|
|
+ */
|
|
|
+ agmt_obj = agmtlist_get_first_agreement_for_replica (r);
|
|
|
+ while (agmt_obj)
|
|
|
+ {
|
|
|
+ agmt = (Repl_Agmt*)object_get_data (agmt_obj);
|
|
|
+ dn = agmt_get_dn_byref(agmt);
|
|
|
+ conn = (Repl_Connection *)agmt_get_connection(agmt);
|
|
|
+ if(conn == NULL){
|
|
|
+ /* no connection for this agreement, move on to the next agmt */
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_extop: the replica (%s), is "
|
|
|
+ "missing the connection. This replica will not be cleaned.\n", slapi_sdn_get_dn(dn));
|
|
|
+ agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ crc = conn_connect(conn);
|
|
|
+ if (CONN_OPERATION_FAILED == crc ){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_extop: failed to connect "
|
|
|
+ "to repl agreement connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_TRANSIENT_ERROR);
|
|
|
+ rc = LDAP_OPERATIONS_ERROR;
|
|
|
+ } else if (CONN_SSL_NOT_ENABLED == crc){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_extop: failed to acquire "
|
|
|
+ "repl agmt connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_FATAL_ERROR);
|
|
|
+ rc = LDAP_OPERATIONS_ERROR;
|
|
|
+ } else {
|
|
|
+ conn_cancel_linger(conn);
|
|
|
+ crc = conn_send_extended_operation(conn, REPL_CLEANRUV_OID, extop_value, NULL, &send_msgid);
|
|
|
+ if (CONN_OPERATION_SUCCESS != crc){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_extop: failed to send "
|
|
|
+ "clean_ruv extended op to repl agmt (%s), error %d\n", slapi_sdn_get_dn(dn), crc);
|
|
|
+ rc = LDAP_OPERATIONS_ERROR;
|
|
|
+ } else {
|
|
|
+ /* success */
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanruv_extop: successfully sent "
|
|
|
+ "extended op to (%s)\n",slapi_sdn_get_dn(dn) );
|
|
|
+ }
|
|
|
+ conn_start_linger(conn);
|
|
|
+ }
|
|
|
+ if(crc != CONN_OPERATION_SUCCESS){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_extop: replica (%s) has not "
|
|
|
+ "been cleaned. You will need to rerun the CLEANALLRUV task on this replica\n",
|
|
|
+ slapi_sdn_get_dn(dn) );
|
|
|
+ rc = LDAP_OPERATIONS_ERROR;
|
|
|
+ }
|
|
|
+ agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* now clean the ruv */
|
|
|
+ replica_execute_cleanruv_task_ext(mtnode_ext->replica, rid);
|
|
|
+
|
|
|
+free_and_return:
|
|
|
+
|
|
|
+ if(rc == 0){
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanruv_extop: cleaned rid (%d)\n", rid);
|
|
|
+ } else {
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_extop: failed to clean rid (%d), error (%d)\n",rid, rc);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mtnode_ext->replica)
|
|
|
+ object_release (mtnode_ext->replica);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Process the REPL_RELEASERUV_OID extended operation
|
|
|
+ *
|
|
|
+ * Once, all the replicas in the replication farm have been cleaned, then
|
|
|
+ * we need to "release" the cleaned_rid, or else we will reject all updates
|
|
|
+ * that come from that rid until we restart the server.
|
|
|
+ *
|
|
|
+ * We set the cleaned_ruv to zero(invalid rid), and then fire off extended
|
|
|
+ * operations to all of the replicas
|
|
|
+ */
|
|
|
+int
|
|
|
+multimaster_extop_releaseruv(Slapi_PBlock *pb){
|
|
|
+ multimaster_mtnode_extension *mtnode_ext;
|
|
|
+ Repl_Connection *conn;
|
|
|
+ const Slapi_DN *dn;
|
|
|
+ Replica *r = NULL;
|
|
|
+ Object *agmt_obj;
|
|
|
+ Repl_Agmt *agmt;
|
|
|
+ ConnResult crc;
|
|
|
+ struct berval *extop_value;
|
|
|
+ char *payload = NULL;
|
|
|
+ char *extop_oid;
|
|
|
+ char *repl_root;
|
|
|
+ char *iter;
|
|
|
+ int send_msgid = 0;
|
|
|
+ int rid = 0;
|
|
|
+ int rc = -1;
|
|
|
+
|
|
|
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
|
|
|
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
|
|
|
+
|
|
|
+ if (NULL == extop_oid || strcmp(extop_oid, REPL_RELEASERUV_OID) != 0 ||
|
|
|
+ NULL == extop_value || NULL == extop_value->bv_val){
|
|
|
+ /* something is wrong, error out */
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(decode_cleanruv_payload(extop_value, &payload)){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL,repl_plugin_name, "releaseruv_extop: failed to decode payload, aborting ext op\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
|
|
|
+ repl_root = ldap_utf8strtok_r(iter, ":", &iter);
|
|
|
+
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "releaseruv_extop: releasing rid (%d)...\n",rid);
|
|
|
+ /*
|
|
|
+ * If we already released this ruv, just return.
|
|
|
+ */
|
|
|
+ if(is_released_rid(rid) || is_already_released_rid()){
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "releaseruv_extop: rid (%d) has already been released, skipping\n",rid);
|
|
|
+ return 0;
|
|
|
+ } else {
|
|
|
+ /* set the released rid, and trigger trimming */
|
|
|
+ set_released_rid((int)rid);
|
|
|
+ trigger_cl_trimming();
|
|
|
+ }
|
|
|
+
|
|
|
+ if((mtnode_ext = replica_config_get_mtnode_by_dn(repl_root)) == NULL){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseruv_extop: failed to get node "
|
|
|
+ "from replication root dn(%s), aborting operation.\n", repl_root);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (mtnode_ext->replica)
|
|
|
+ object_acquire (mtnode_ext->replica);
|
|
|
+ if (mtnode_ext->replica == NULL){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseruv_extop: replica is missing from (%s), "
|
|
|
+ "aborting operation.\n", repl_root);
|
|
|
+ rc = LDAP_OPERATIONS_ERROR;
|
|
|
+ goto free_and_return;
|
|
|
+ }
|
|
|
+ r = (Replica*)object_get_data (mtnode_ext->replica);
|
|
|
+ /*
|
|
|
+ * Loop over the agreements, and send out extended ops
|
|
|
+ */
|
|
|
+ agmt_obj = agmtlist_get_first_agreement_for_replica (r);
|
|
|
+ while (agmt_obj)
|
|
|
+ {
|
|
|
+ agmt = (Repl_Agmt*)object_get_data (agmt_obj);
|
|
|
+ dn = agmt_get_dn_byref(agmt);
|
|
|
+ conn = (Repl_Connection *)agmt_get_connection(agmt);
|
|
|
+ if(conn == NULL){
|
|
|
+ /* no connection for this agreement, log error, and move on */
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseruv_extop: the replica (%s), is "
|
|
|
+ "missing the connection. This replica will not be cleaned.\n", slapi_sdn_get_dn(dn));
|
|
|
+ agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ crc = conn_connect(conn);
|
|
|
+ if (CONN_OPERATION_FAILED == crc ){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseruv_extop: failed to connect "
|
|
|
+ "to repl agreement connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_TRANSIENT_ERROR);
|
|
|
+ rc = LDAP_OPERATIONS_ERROR;
|
|
|
+ } else if (CONN_SSL_NOT_ENABLED == crc){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseruv_extop: failed to acquire "
|
|
|
+ "repl agmt connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_FATAL_ERROR);
|
|
|
+ rc = LDAP_OPERATIONS_ERROR;
|
|
|
+ } else {
|
|
|
+ conn_cancel_linger(conn);
|
|
|
+ crc = conn_send_extended_operation(conn, REPL_RELEASERUV_OID, extop_value, NULL, &send_msgid);
|
|
|
+ if (CONN_OPERATION_SUCCESS != crc){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseruv_extop: failed to send "
|
|
|
+ "releaseruv extended op to repl agmt (%s), error %d\n", slapi_sdn_get_dn(dn), crc);
|
|
|
+ rc = LDAP_OPERATIONS_ERROR;
|
|
|
+ } else {
|
|
|
+ /* success */
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "releaseruv_extop: successfully sent "
|
|
|
+ "extended op to (%s)\n",slapi_sdn_get_dn(dn) );
|
|
|
+ rc = 0;
|
|
|
+ }
|
|
|
+ conn_start_linger(conn);
|
|
|
+ }
|
|
|
+ if(crc){
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseruv_extop: replica (%s) has not "
|
|
|
+ "been cleaned. You will need to rerun the RELEASERUV task on this replica\n",
|
|
|
+ slapi_sdn_get_dn(dn) );
|
|
|
+ }
|
|
|
+ agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
|
|
|
+ }
|
|
|
+
|
|
|
+free_and_return:
|
|
|
+ /*
|
|
|
+ * Set the rid as "ALREADY_RELEASED, and remove the cleaned ruv
|
|
|
+ */
|
|
|
+ if(rc == 0){
|
|
|
+ set_released_rid(ALREADY_RELEASED);
|
|
|
+ delete_cleaned_rid();
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "releaseruv_extop: released rid (%d) successfully\n", rid);
|
|
|
+ } else {
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseruv_extop: failed to release rid(%d), error (%d), please retry the task\n",rid, rc);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(mtnode_ext->replica)
|
|
|
+ object_release (mtnode_ext->replica);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* This plugin entry point is a noop entry
|
|
|
* point. It's used when registering extops that
|