when performing a recovery,
[rusty/ctdb.git] / server / ctdb_recoverd.c
index f910b3ec69df974c790f91c8d384e5979ac78286..c0d5b17f151fb176c3b9e8cc4038371954e18058 100644 (file)
@@ -212,7 +212,7 @@ static int run_startrecovery_eventscript(struct ctdb_recoverd *rec, struct ctdb_
 static void async_getcap_callback(struct ctdb_context *ctdb, uint32_t node_pnn, int32_t res, TDB_DATA outdata, void *callback_data)
 {
        if ( (outdata.dsize != sizeof(uint32_t)) || (outdata.dptr == NULL) ) {
-               DEBUG(DEBUG_ERR, (__location__ " Invalid lenght/pointer for getcap callback : %u %p\n",  (unsigned)outdata.dsize, outdata.dptr));
+               DEBUG(DEBUG_ERR, (__location__ " Invalid length/pointer for getcap callback : %u %p\n",  (unsigned)outdata.dsize, outdata.dptr));
                return;
        }
        if (node_pnn < ctdb->num_nodes) {
@@ -1228,6 +1228,7 @@ static void reload_nodes_file(struct ctdb_context *ctdb)
 }
 
 static int ctdb_reload_remote_public_ips(struct ctdb_context *ctdb,
+                                        struct ctdb_recoverd *rec,
                                         struct ctdb_node_map *nodemap,
                                         uint32_t *culprit)
 {
@@ -1274,6 +1275,13 @@ static int ctdb_reload_remote_public_ips(struct ctdb_context *ctdb,
                        return -1;
                }
 
+               if (rec->ip_check_disable_ctx == NULL) {
+                       if (verify_remote_ip_allocation(ctdb, ctdb->nodes[j]->known_public_ips)) {
+                               DEBUG(DEBUG_ERR,("Node %d has inconsistent public ip allocation and needs update.\n", ctdb->nodes[j]->pnn));
+                               rec->need_takeover_run = true;
+                       }
+               }
+
                /* grab a new shiny list of public ips from the node */
                ret = ctdb_ctrl_get_public_ips_flags(ctdb,
                                        CONTROL_TIMEOUT(),
@@ -1294,6 +1302,41 @@ static int ctdb_reload_remote_public_ips(struct ctdb_context *ctdb,
        return 0;
 }
 
+/* when we start a recovery, make sure all nodes use the same reclock file
+   setting
+*/
+static int sync_recovery_lock_file_across_cluster(struct ctdb_recoverd *rec)
+{
+       struct ctdb_context *ctdb = rec->ctdb;
+       TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+       TDB_DATA data;
+       uint32_t *nodes;
+
+       if (ctdb->recovery_lock_file == NULL) {
+               data.dptr  = NULL;
+               data.dsize = 0;
+       } else {
+               data.dsize = strlen(ctdb->recovery_lock_file) + 1;
+               data.dptr  = (uint8_t *)ctdb->recovery_lock_file;
+       }
+
+       nodes = list_of_active_nodes(ctdb, rec->nodemap, tmp_ctx, true);
+       if (ctdb_client_async_control(ctdb, CTDB_CONTROL_SET_RECLOCK_FILE,
+                                       nodes, 0,
+                                       CONTROL_TIMEOUT(),
+                                       false, data,
+                                       NULL, NULL,
+                                       rec) != 0) {
+               DEBUG(DEBUG_ERR, (__location__ " Failed to sync reclock file settings\n"));
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       talloc_free(tmp_ctx);
+       return 0;
+}
+
+
 /*
   we are the recmaster, and recovery is needed - start a recovery run
  */
@@ -1342,7 +1385,7 @@ static int do_recovery(struct ctdb_recoverd *rec,
                        return -1;
                }
                ctdb_ctrl_report_recd_lock_latency(ctdb, CONTROL_TIMEOUT(), timeval_elapsed(&start_time));
-               DEBUG(DEBUG_ERR,("Recovery lock taken successfully by recovery daemon\n"));
+               DEBUG(DEBUG_NOTICE,("Recovery lock taken successfully by recovery daemon\n"));
        }
 
        DEBUG(DEBUG_NOTICE, (__location__ " Recovery initiated due to problem with node %u\n", rec->last_culprit_node));
@@ -1380,6 +1423,11 @@ static int do_recovery(struct ctdb_recoverd *rec,
        DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated db priority for all databases\n"));
 
 
+       /* update all other nodes to use the same setting for reclock files
+          as the local recovery master.
+       */
+       sync_recovery_lock_file_across_cluster(rec);
+
        /* set recovery mode to active on all nodes */
        ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE);
        if (ret != 0) {
@@ -1568,7 +1616,7 @@ static int do_recovery(struct ctdb_recoverd *rec,
        /*
          tell nodes to takeover their public IPs
         */
-       ret = ctdb_reload_remote_public_ips(ctdb, nodemap, &culprit);
+       ret = ctdb_reload_remote_public_ips(ctdb, rec, nodemap, &culprit);
        if (ret != 0) {
                DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
                                 culprit));
@@ -1885,6 +1933,29 @@ static void reenable_ip_check(struct event_context *ev, struct timed_event *te,
        rec->ip_check_disable_ctx = NULL;
 }
 
+
+static void recd_update_ip_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+                            TDB_DATA data, void *private_data)
+{
+       struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+       struct ctdb_public_ip *ip;
+
+       if (rec->recmaster != rec->ctdb->pnn) {
+               DEBUG(DEBUG_INFO,("Not recmaster, ignore update ip message\n"));
+               return;
+       }
+
+       if (data.dsize != sizeof(struct ctdb_public_ip)) {
+               DEBUG(DEBUG_ERR,(__location__ " Incorrect size of recd update ip message. Was %zd but expected %zd bytes\n", data.dsize, sizeof(struct ctdb_public_ip)));
+               return;
+       }
+
+       ip = (struct ctdb_public_ip *)data.dptr;
+
+       update_ip_assignment_tree(rec->ctdb, ip);
+}
+
+
 static void disable_ip_check_handler(struct ctdb_context *ctdb, uint64_t srvid, 
                             TDB_DATA data, void *private_data)
 {
@@ -1961,7 +2032,7 @@ static void process_ipreallocate_requests(struct ctdb_context *ctdb, struct ctdb
        /* update the list of public ips that a node can handle for
           all connected nodes
        */
-       ret = ctdb_reload_remote_public_ips(ctdb, rec->nodemap, &culprit);
+       ret = ctdb_reload_remote_public_ips(ctdb, rec, rec->nodemap, &culprit);
        if (ret != 0) {
                DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
                                 culprit));
@@ -2414,9 +2485,9 @@ static enum monitor_result verify_recmaster(struct ctdb_recoverd *rec, struct ct
 }
 
 
-/* called to check that the allocation of public ip addresses is ok.
+/* called to check that the local allocation of public ip addresses is ok.
 */
-static int verify_ip_allocation(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, uint32_t pnn)
+static int verify_local_ip_allocation(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, uint32_t pnn)
 {
        TALLOC_CTX *mem_ctx = talloc_new(NULL);
        struct ctdb_control_get_ifaces *ifaces = NULL;
@@ -2856,6 +2927,9 @@ static void monitor_cluster(struct ctdb_context *ctdb)
        /* register a message port for disabling the ip check for a short while */
        ctdb_set_message_handler(ctdb, CTDB_SRVID_DISABLE_IP_CHECK, disable_ip_check_handler, rec);
 
+       /* register a message port for updating the recovery daemons node assignment for an ip */
+       ctdb_set_message_handler(ctdb, CTDB_SRVID_RECD_UPDATE_IP, recd_update_ip_handler, rec);
+
 again:
        if (mem_ctx) {
                talloc_free(mem_ctx);
@@ -3088,7 +3162,7 @@ again:
         */ 
        if (ctdb->do_checkpublicip) {
                if (rec->ip_check_disable_ctx == NULL) {
-                       if (verify_ip_allocation(ctdb, rec, pnn) != 0) {
+                       if (verify_local_ip_allocation(ctdb, rec, pnn) != 0) {
                                DEBUG(DEBUG_ERR, (__location__ " Public IPs were inconsistent.\n"));
                        }
                }
@@ -3353,7 +3427,7 @@ again:
                /* update the list of public ips that a node can handle for
                   all connected nodes
                */
-               ret = ctdb_reload_remote_public_ips(ctdb, nodemap, &culprit);
+               ret = ctdb_reload_remote_public_ips(ctdb, rec, nodemap, &culprit);
                if (ret != 0) {
                        DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
                                         culprit));
@@ -3496,7 +3570,7 @@ int ctdb_start_recoverd(struct ctdb_context *ctdb)
                exit(1);
        }
 
-       DEBUG(DEBUG_NOTICE, (__location__ " Created PIPE FD:%d to recovery daemon\n", fd[0]));
+       DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d to recovery daemon\n", fd[0]));
 
        event_add_fd(ctdb->ev, ctdb, fd[0], EVENT_FD_READ|EVENT_FD_AUTOCLOSE, 
                     ctdb_recoverd_parent, &fd[0]);