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"
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) {
{
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;
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;
}
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 (lmaster == ctdb->pnn) {
ctdb_send_dmaster_reply(ctdb_db, header, *key, *data,
c->hdr.srcnode, c->hdr.reqid);
return;
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 (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 (reqid != state->reqid) {
+ 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) {
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 */
/* 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));
+ }
}
}
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,
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);
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);
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;
}
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);
}
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;
}
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"));
}
/*
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);
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);
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;
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;
}
{
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);
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);