Revert "Add a new header flag for "migrated with data" and set this to 1"
[sahlberg/ctdb.git] / server / ctdb_call.c
index 89a8ccc1bcfbf1a62e387cd3e61b05f7a77c2906..ed741ed0a9d5f4cd7a6b9bf26836b4ee8760265d 100644 (file)
@@ -5,7 +5,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 /*
   see http://wiki.samba.org/index.php/Samba_%26_Clustering for
   protocol design and packet details
 */
 #include "includes.h"
-#include "lib/events/events.h"
+#include "lib/tevent/tevent.h"
 #include "lib/tdb/include/tdb.h"
 #include "lib/util/dlinklist.h"
 #include "system/network.h"
@@ -70,6 +69,11 @@ static void ctdb_send_error(struct ctdb_context *ctdb,
        char *msg;
        int msglen, len;
 
+       if (ctdb->methods == NULL) {
+               DEBUG(DEBUG_INFO,(__location__ " Failed to send error. Transport is DOWN\n"));
+               return;
+       }
+
        va_start(ap, fmt);
        msg = talloc_vasprintf(ctdb, fmt, ap);
        if (msg == NULL) {
@@ -105,7 +109,7 @@ static void ctdb_call_send_redirect(struct ctdb_context *ctdb,
 {
        
        uint32_t lmaster = ctdb_lmaster(ctdb, &key);
-       if (ctdb->vnn == lmaster) {
+       if (ctdb->pnn == lmaster) {
                c->hdr.destnode = header->dmaster;
        } else if ((c->hopcount % ctdb->tunable.max_redirect_count) == 0) {
                c->hdr.destnode = lmaster;
@@ -134,15 +138,20 @@ static void ctdb_send_dmaster_reply(struct ctdb_db_context *ctdb_db,
        int ret, len;
        TALLOC_CTX *tmp_ctx;
 
-       if (ctdb->vnn != ctdb_lmaster(ctdb, &key)) {
-               DEBUG(0,(__location__ " Caller is not lmaster!\n"));
+       if (ctdb->pnn != ctdb_lmaster(ctdb, &key)) {
+               DEBUG(DEBUG_ALERT,(__location__ " Caller is not lmaster!\n"));
                return;
        }
 
        header->dmaster = new_dmaster;
        ret = ctdb_ltdb_store(ctdb_db, key, header, data);
        if (ret != 0) {
-               ctdb_fatal(ctdb, "ctdb_req_dmaster unable to update dmaster");
+               ctdb_fatal(ctdb, "ctdb_send_dmaster_reply unable to update dmaster");
+               return;
+       }
+
+       if (ctdb->methods == NULL) {
+               ctdb_fatal(ctdb, "ctdb_send_dmaster_reply cant update dmaster since transport is down");
                return;
        }
 
@@ -187,7 +196,16 @@ static void ctdb_call_send_dmaster(struct ctdb_db_context *ctdb_db,
        int len;
        uint32_t lmaster = ctdb_lmaster(ctdb, key);
 
-       if (lmaster == ctdb->vnn) {
+       if (ctdb->methods == NULL) {
+               ctdb_fatal(ctdb, "Failed ctdb_call_send_dmaster since transport is down");
+               return;
+       }
+
+       if (data->dsize != 0) {
+               header->flags &= CTDB_REC_FLAG_MIGRATED_WITH_DATA;
+       }
+
+       if (lmaster == ctdb->pnn) {
                ctdb_send_dmaster_reply(ctdb_db, header, *key, *data, 
                                        c->hdr.srcnode, c->hdr.reqid);
                return;
@@ -224,44 +242,71 @@ static void ctdb_call_send_dmaster(struct ctdb_db_context *ctdb_db,
   must be called with the chainlock held. This function releases the chainlock
 */
 static void ctdb_become_dmaster(struct ctdb_db_context *ctdb_db, 
-                               uint32_t reqid, TDB_DATA key, TDB_DATA data,
+                               struct ctdb_req_header *hdr,
+                               TDB_DATA key, TDB_DATA data,
                                uint64_t rsn)
 {
        struct ctdb_call_state *state;
        struct ctdb_context *ctdb = ctdb_db->ctdb;
        struct ctdb_ltdb_header header;
+       int ret;
 
-       DEBUG(2,("vnn %u dmaster response %08x\n", ctdb->vnn, ctdb_hash(&key)));
+       DEBUG(DEBUG_DEBUG,("pnn %u dmaster response %08x\n", ctdb->pnn, ctdb_hash(&key)));
 
        ZERO_STRUCT(header);
        header.rsn = rsn + 1;
-       header.dmaster = ctdb->vnn;
+       header.dmaster = ctdb->pnn;
 
        if (ctdb_ltdb_store(ctdb_db, key, &header, data) != 0) {
                ctdb_fatal(ctdb, "ctdb_reply_dmaster store failed\n");
-               ctdb_ltdb_unlock(ctdb_db, key);
+
+               ret = ctdb_ltdb_unlock(ctdb_db, key);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+               }
                return;
        }
 
-       state = ctdb_reqid_find(ctdb, reqid, struct ctdb_call_state);
+       state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);
 
        if (state == NULL) {
-               DEBUG(0,("vnn %u Invalid reqid %u in ctdb_become_dmaster\n",
-                        ctdb->vnn, reqid));
-               ctdb_ltdb_unlock(ctdb_db, key);
+               DEBUG(DEBUG_ERR,("pnn %u Invalid reqid %u in ctdb_become_dmaster from node %u\n",
+                        ctdb->pnn, hdr->reqid, hdr->srcnode));
+
+               ret = ctdb_ltdb_unlock(ctdb_db, key);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+               }
                return;
        }
 
-       if (reqid != state->reqid) {
+       if (key.dsize != state->call->key.dsize || memcmp(key.dptr, state->call->key.dptr, key.dsize)) {
+               DEBUG(DEBUG_ERR, ("Got bogus DMASTER packet reqid:%u from node %u. Key does not match key held in matching idr.\n", hdr->reqid, hdr->srcnode));
+
+               ret = ctdb_ltdb_unlock(ctdb_db, key);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+               }
+               return;
+       }
+
+       if (hdr->reqid != state->reqid) {
                /* we found a record  but it was the wrong one */
-               DEBUG(0, ("Dropped orphan in ctdb_become_dmaster with reqid:%u\n",reqid));
-               ctdb_ltdb_unlock(ctdb_db, key);
+               DEBUG(DEBUG_ERR, ("Dropped orphan in ctdb_become_dmaster with reqid:%u\n from node %u", hdr->reqid, hdr->srcnode));
+
+               ret = ctdb_ltdb_unlock(ctdb_db, key);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+               }
                return;
        }
 
-       ctdb_call_local(ctdb_db, &state->call, &header, state, &data, ctdb->vnn);
+       ctdb_call_local(ctdb_db, state->call, &header, state, &data);
 
-       ctdb_ltdb_unlock(ctdb_db, state->call.key);
+       ret = ctdb_ltdb_unlock(ctdb_db, state->call->key);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+       }
 
        state->state = CTDB_CALL_DONE;
        if (state->async.fn) {
@@ -306,26 +351,38 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
                return;
        }
        if (ret == -2) {
-               DEBUG(2,(__location__ " deferring ctdb_request_dmaster\n"));
+               DEBUG(DEBUG_INFO,(__location__ " deferring ctdb_request_dmaster\n"));
                return;
        }
 
-       if (ctdb_lmaster(ctdb, &key) != ctdb->vnn) {
-               DEBUG(0,("vnn %u dmaster request to non-lmaster lmaster=%u\n",
-                        ctdb->vnn, ctdb_lmaster(ctdb, &key)));
+       if (ctdb_lmaster(ctdb, &key) != ctdb->pnn) {
+               DEBUG(DEBUG_ALERT,("pnn %u dmaster request to non-lmaster lmaster=%u gen=%u curgen=%u\n",
+                        ctdb->pnn, ctdb_lmaster(ctdb, &key), 
+                        hdr->generation, ctdb->vnn_map->generation));
                ctdb_fatal(ctdb, "ctdb_req_dmaster to non-lmaster");
        }
 
-       DEBUG(2,("vnn %u dmaster request on %08x for %u from %u\n", 
-                ctdb->vnn, ctdb_hash(&key), c->dmaster, c->hdr.srcnode));
+       DEBUG(DEBUG_DEBUG,("pnn %u dmaster request on %08x for %u from %u\n", 
+                ctdb->pnn, ctdb_hash(&key), c->dmaster, c->hdr.srcnode));
 
        /* its a protocol error if the sending node is not the current dmaster */
        if (header.dmaster != hdr->srcnode) {
-               DEBUG(0,("vnn %u dmaster request non-master %u dmaster=%u key %08x dbid 0x%08x\n",
-                        ctdb->vnn, hdr->srcnode, header.dmaster, ctdb_hash(&key),
-                        ctdb_db->db_id));
-               ctdb_fatal(ctdb, "ctdb_req_dmaster from non-master");
-               return;
+               DEBUG(DEBUG_ALERT,("pnn %u dmaster request for new-dmaster %u from non-master %u real-dmaster=%u key %08x dbid 0x%08x gen=%u curgen=%u c->rsn=%llu header.rsn=%llu reqid=%u keyval=0x%08x\n",
+                        ctdb->pnn, c->dmaster, hdr->srcnode, header.dmaster, ctdb_hash(&key),
+                        ctdb_db->db_id, hdr->generation, ctdb->vnn_map->generation,
+                        (unsigned long long)c->rsn, (unsigned long long)header.rsn, c->hdr.reqid,
+                        (key.dsize >= 4)?(*(uint32_t *)key.dptr):0));
+               if (header.rsn != 0 || header.dmaster != ctdb->pnn) {
+                       ctdb_fatal(ctdb, "ctdb_req_dmaster from non-master");
+                       return;
+               }
+       }
+
+       if (header.rsn > c->rsn) {
+               DEBUG(DEBUG_ALERT,("pnn %u dmaster request with older RSN new-dmaster %u from %u real-dmaster=%u key %08x dbid 0x%08x gen=%u curgen=%u c->rsn=%llu header.rsn=%llu reqid=%u\n",
+                        ctdb->pnn, c->dmaster, hdr->srcnode, header.dmaster, ctdb_hash(&key),
+                        ctdb_db->db_id, hdr->generation, ctdb->vnn_map->generation,
+                        (unsigned long long)c->rsn, (unsigned long long)header.rsn, c->hdr.reqid));
        }
 
        /* use the rsn from the sending node */
@@ -333,11 +390,15 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
 
        /* check if the new dmaster is the lmaster, in which case we
           skip the dmaster reply */
-       if (c->dmaster == ctdb->vnn) {
-               ctdb_become_dmaster(ctdb_db, hdr->reqid, key, data, c->rsn);
+       if (c->dmaster == ctdb->pnn) {
+               ctdb_become_dmaster(ctdb_db, hdr, key, data, c->rsn);
        } else {
                ctdb_send_dmaster_reply(ctdb_db, &header, key, data, c->dmaster, hdr->reqid);
-               ctdb_ltdb_unlock(ctdb_db, key);
+
+               ret = ctdb_ltdb_unlock(ctdb_db, key);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+               }
        }
 }
 
@@ -352,9 +413,15 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
        struct ctdb_reply_call *r;
        int ret, len;
        struct ctdb_ltdb_header header;
-       struct ctdb_call call;
+       struct ctdb_call *call;
        struct ctdb_db_context *ctdb_db;
 
+       if (ctdb->methods == NULL) {
+               DEBUG(DEBUG_INFO,(__location__ " Failed ctdb_request_call. Transport is DOWN\n"));
+               return;
+       }
+
+
        ctdb_db = find_ctdb_db(ctdb, c->db_id);
        if (!ctdb_db) {
                ctdb_send_error(ctdb, hdr, -1,
@@ -363,70 +430,85 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
                return;
        }
 
-       call.call_id  = c->callid;
-       call.key.dptr = c->data;
-       call.key.dsize = c->keylen;
-       call.call_data.dptr = c->data + c->keylen;
-       call.call_data.dsize = c->calldatalen;
+       call = talloc(hdr, struct ctdb_call);
+       CTDB_NO_MEMORY_FATAL(ctdb, call);
+
+       call->call_id  = c->callid;
+       call->key.dptr = c->data;
+       call->key.dsize = c->keylen;
+       call->call_data.dptr = c->data + c->keylen;
+       call->call_data.dsize = c->calldatalen;
 
        /* determine if we are the dmaster for this key. This also
           fetches the record data (if any), thus avoiding a 2nd fetch of the data 
           if the call will be answered locally */
 
-       ret = ctdb_ltdb_lock_fetch_requeue(ctdb_db, call.key, &header, hdr, &data,
+       ret = ctdb_ltdb_lock_fetch_requeue(ctdb_db, call->key, &header, hdr, &data,
                                           ctdb_call_input_pkt, ctdb, False);
        if (ret == -1) {
                ctdb_send_error(ctdb, hdr, ret, "ltdb fetch failed in ctdb_request_call");
                return;
        }
        if (ret == -2) {
-               DEBUG(2,(__location__ " deferred ctdb_request_call\n"));
+               DEBUG(DEBUG_INFO,(__location__ " deferred ctdb_request_call\n"));
                return;
        }
 
        /* if we are not the dmaster, then send a redirect to the
           requesting node */
-       if (header.dmaster != ctdb->vnn) {
+       if (header.dmaster != ctdb->pnn) {
                talloc_free(data.dptr);
-               ctdb_call_send_redirect(ctdb, call.key, c, &header);
-               ctdb_ltdb_unlock(ctdb_db, call.key);
-               return;
-       }
+               ctdb_call_send_redirect(ctdb, call->key, c, &header);
 
-       if (c->hopcount > ctdb->statistics.max_hop_count) {
-               ctdb->statistics.max_hop_count = c->hopcount;
+               ret = ctdb_ltdb_unlock(ctdb_db, call->key);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+               }
+               return;
        }
 
-       /* if this nodes has done enough consecutive calls on the same record
-          then give them the record
-          or if the node requested an immediate migration
-       */
-       if ( c->hdr.srcnode != ctdb->vnn &&
-            ((header.laccessor == c->hdr.srcnode
-              && header.lacount >= ctdb->tunable.max_lacount)
-             || (c->flags & CTDB_IMMEDIATE_MIGRATION)) ) {
-               DEBUG(2,("vnn %u starting migration of %08x to %u\n", 
-                        ctdb->vnn, ctdb_hash(&call.key), c->hdr.srcnode));
-               ctdb_call_send_dmaster(ctdb_db, c, &header, &call.key, &data);
-               talloc_free(data.dptr);
-               ctdb_ltdb_unlock(ctdb_db, call.key);
-               return;
+       CTDB_UPDATE_STAT(ctdb, max_hop_count, c->hopcount);
+
+       /* Try if possible to migrate the record off to the caller node.
+        * From the clients perspective a fetch of the data is just as 
+        * expensive as a migration.
+        */
+       if (c->hdr.srcnode != ctdb->pnn) {
+               if (ctdb_db->transaction_active) {
+                       DEBUG(DEBUG_INFO, (__location__ " refusing migration"
+                             " of key %s while transaction is active\n",
+                             (char *)call->key.dptr));
+               } else {
+                       DEBUG(DEBUG_DEBUG,("pnn %u starting migration of %08x to %u\n",
+                                ctdb->pnn, ctdb_hash(&(call->key)), c->hdr.srcnode));
+                       ctdb_call_send_dmaster(ctdb_db, c, &header, &(call->key), &data);
+                       talloc_free(data.dptr);
+
+                       ret = ctdb_ltdb_unlock(ctdb_db, call->key);
+                       if (ret != 0) {
+                               DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+                       }
+                       return;
+               }
        }
 
-       ctdb_call_local(ctdb_db, &call, &header, hdr, &data, c->hdr.srcnode);
+       ctdb_call_local(ctdb_db, call, &header, hdr, &data);
 
-       ctdb_ltdb_unlock(ctdb_db, call.key);
+       ret = ctdb_ltdb_unlock(ctdb_db, call->key);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+       }
 
-       len = offsetof(struct ctdb_reply_call, data) + call.reply_data.dsize;
+       len = offsetof(struct ctdb_reply_call, data) + call->reply_data.dsize;
        r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CALL, len, 
                                    struct ctdb_reply_call);
        CTDB_NO_MEMORY_FATAL(ctdb, r);
        r->hdr.destnode  = hdr->srcnode;
        r->hdr.reqid     = hdr->reqid;
-       r->status        = call.status;
-       r->datalen       = call.reply_data.dsize;
-       if (call.reply_data.dsize) {
-               memcpy(&r->data[0], call.reply_data.dptr, call.reply_data.dsize);
+       r->status        = call->status;
+       r->datalen       = call->reply_data.dsize;
+       if (call->reply_data.dsize) {
+               memcpy(&r->data[0], call->reply_data.dptr, call->reply_data.dsize);
        }
 
        ctdb_queue_packet(ctdb, &r->hdr);
@@ -447,19 +529,19 @@ void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 
        state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);
        if (state == NULL) {
-               DEBUG(0, (__location__ " reqid %u not found\n", hdr->reqid));
+               DEBUG(DEBUG_ERR, (__location__ " reqid %u not found\n", hdr->reqid));
                return;
        }
 
        if (hdr->reqid != state->reqid) {
                /* we found a record  but it was the wrong one */
-               DEBUG(0, ("Dropped orphaned call reply with reqid:%u\n",hdr->reqid));
+               DEBUG(DEBUG_ERR, ("Dropped orphaned call reply with reqid:%u\n",hdr->reqid));
                return;
        }
 
-       state->call.reply_data.dptr = c->data;
-       state->call.reply_data.dsize = c->datalen;
-       state->call.status = c->status;
+       state->call->reply_data.dptr = c->data;
+       state->call->reply_data.dsize = c->datalen;
+       state->call->status = c->status;
 
        talloc_steal(state, c);
 
@@ -486,7 +568,7 @@ void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 
        ctdb_db = find_ctdb_db(ctdb, c->db_id);
        if (ctdb_db == NULL) {
-               DEBUG(0,("Unknown db_id 0x%x in ctdb_reply_dmaster\n", c->db_id));
+               DEBUG(DEBUG_ERR,("Unknown db_id 0x%x in ctdb_reply_dmaster\n", c->db_id));
                return;
        }
        
@@ -501,11 +583,11 @@ void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
                return;
        }
        if (ret != 0) {
-               DEBUG(0,(__location__ " Failed to get lock in ctdb_reply_dmaster\n"));
+               DEBUG(DEBUG_ERR,(__location__ " Failed to get lock in ctdb_reply_dmaster\n"));
                return;
        }
 
-       ctdb_become_dmaster(ctdb_db, hdr->reqid, key, data, c->rsn);
+       ctdb_become_dmaster(ctdb_db, hdr, key, data, c->rsn);
 }
 
 
@@ -519,14 +601,14 @@ void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
 
        state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);
        if (state == NULL) {
-               DEBUG(0,("vnn %u Invalid reqid %u in ctdb_reply_error\n",
-                        ctdb->vnn, hdr->reqid));
+               DEBUG(DEBUG_ERR,("pnn %u Invalid reqid %u in ctdb_reply_error\n",
+                        ctdb->pnn, hdr->reqid));
                return;
        }
 
        if (hdr->reqid != state->reqid) {
                /* we found a record  but it was the wrong one */
-               DEBUG(0, ("Dropped orphaned error reply with reqid:%u\n",hdr->reqid));
+               DEBUG(DEBUG_ERR, ("Dropped orphaned error reply with reqid:%u\n",hdr->reqid));
                return;
        }
 
@@ -569,10 +651,10 @@ static void ctdb_call_resend(struct ctdb_call_state *state)
        state->c->hdr.generation = state->generation;
 
        /* send the packet to ourselves, it will be redirected appropriately */
-       state->c->hdr.destnode = ctdb->vnn;
+       state->c->hdr.destnode = ctdb->pnn;
 
        ctdb_queue_packet(ctdb, &state->c->hdr);
-       DEBUG(0,("resent ctdb_call\n"));
+       DEBUG(DEBUG_NOTICE,("resent ctdb_call\n"));
 }
 
 /*
@@ -621,10 +703,12 @@ struct ctdb_call_state *ctdb_call_local_send(struct ctdb_db_context *ctdb_db,
        talloc_steal(state, data->dptr);
 
        state->state = CTDB_CALL_DONE;
-       state->call = *call;
+       state->call  = talloc(state, struct ctdb_call);
+       CTDB_NO_MEMORY_NULL(ctdb, state->call);
+       *(state->call) = *call;
        state->ctdb_db = ctdb_db;
 
-       ret = ctdb_call_local(ctdb_db, &state->call, header, state, data, ctdb->vnn);
+       ret = ctdb_call_local(ctdb_db, state->call, header, state, data);
 
        event_add_timed(ctdb->ev, state, timeval_zero(), call_local_trigger, state);
 
@@ -646,8 +730,16 @@ struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctd
        struct ctdb_call_state *state;
        struct ctdb_context *ctdb = ctdb_db->ctdb;
 
+       if (ctdb->methods == NULL) {
+               DEBUG(DEBUG_INFO,(__location__ " Failed send packet. Transport is down\n"));
+               return NULL;
+       }
+
        state = talloc_zero(ctdb_db, struct ctdb_call_state);
        CTDB_NO_MEMORY_NULL(ctdb, state);
+       state->call = talloc(state, struct ctdb_call);
+       CTDB_NO_MEMORY_NULL(ctdb, state->call);
+
        state->reqid = ctdb_reqid_new(ctdb, state);
        state->ctdb_db = ctdb_db;
        talloc_set_destructor(state, ctdb_call_destructor);
@@ -669,9 +761,9 @@ struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctd
        memcpy(&state->c->data[0], call->key.dptr, call->key.dsize);
        memcpy(&state->c->data[call->key.dsize], 
               call->call_data.dptr, call->call_data.dsize);
-       state->call                = *call;
-       state->call.call_data.dptr = &state->c->data[call->key.dsize];
-       state->call.key.dptr       = &state->c->data[0];
+       *(state->call)              = *call;
+       state->call->call_data.dptr = &state->c->data[call->key.dsize];
+       state->call->key.dptr       = &state->c->data[0];
 
        state->state  = CTDB_CALL_WAIT;
        state->generation = ctdb->vnn_map->generation;
@@ -700,16 +792,16 @@ int ctdb_daemon_call_recv(struct ctdb_call_state *state, struct ctdb_call *call)
                return -1;
        }
 
-       if (state->call.reply_data.dsize) {
-               call->reply_data.dptr = talloc_memdup(state->ctdb_db->ctdb,
-                                                     state->call.reply_data.dptr,
-                                                     state->call.reply_data.dsize);
-               call->reply_data.dsize = state->call.reply_data.dsize;
+       if (state->call->reply_data.dsize) {
+               call->reply_data.dptr = talloc_memdup(call,
+                                                     state->call->reply_data.dptr,
+                                                     state->call->reply_data.dsize);
+               call->reply_data.dsize = state->call->reply_data.dsize;
        } else {
                call->reply_data.dptr = NULL;
                call->reply_data.dsize = 0;
        }
-       call->status = state->call.status;
+       call->status = state->call->status;
        talloc_free(state);
        return 0;
 }
@@ -722,6 +814,11 @@ void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode)
 {
        struct ctdb_req_keepalive *r;
        
+       if (ctdb->methods == NULL) {
+               DEBUG(DEBUG_INFO,(__location__ " Failed to send keepalive. Transport is DOWN\n"));
+               return;
+       }
+
        r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REQ_KEEPALIVE,
                                    sizeof(struct ctdb_req_keepalive), 
                                    struct ctdb_req_keepalive);
@@ -729,7 +826,7 @@ void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode)
        r->hdr.destnode  = destnode;
        r->hdr.reqid     = 0;
        
-       ctdb->statistics.keepalive_packets_sent++;
+       CTDB_INCREMENT_STAT(ctdb, keepalive_packets_sent);
 
        ctdb_queue_packet(ctdb, &r->hdr);