mirror of
https://github.com/samba-team/samba.git
synced 2025-08-26 01:49:31 +03:00
merge from tridge
(This used to be ctdb commit 7bca79ad6357149fd7c6b28ce4b05de3d223a7de)
This commit is contained in:
@ -29,7 +29,7 @@ CTDB_COMMON_OBJ = common/ctdb.o common/ctdb_daemon.o common/ctdb_client.o \
|
||||
common/ctdb_io.o common/util.o common/ctdb_util.o \
|
||||
common/ctdb_call.o common/ctdb_ltdb.o common/ctdb_lockwait.o \
|
||||
common/ctdb_message.o common/cmdline.o common/ctdb_control.o \
|
||||
lib/util/debug.o common/ctdb_recover.o common/ctdb_traverse.o
|
||||
lib/util/debug.o common/ctdb_recover.o common/ctdb_freeze.o common/ctdb_traverse.o
|
||||
|
||||
CTDB_TCP_OBJ = tcp/tcp_connect.o tcp/tcp_io.o tcp/tcp_init.o
|
||||
|
||||
|
@ -261,8 +261,12 @@ void ctdb_recv_pkt(struct ctdb_context *ctdb, uint8_t *data, uint32_t length)
|
||||
|
||||
switch (hdr->operation) {
|
||||
case CTDB_REQ_CALL:
|
||||
/* verify that the remote node that sent us the call
|
||||
is running in the same generation instance as this node
|
||||
case CTDB_REPLY_CALL:
|
||||
case CTDB_REQ_DMASTER:
|
||||
case CTDB_REPLY_DMASTER:
|
||||
/* for ctdb_call inter-node operations verify that the
|
||||
remote node that sent us the call is running in the
|
||||
same generation instance as this node
|
||||
*/
|
||||
if (ctdb->vnn_map->generation != hdr->generation) {
|
||||
DEBUG(0,(__location__ " ctdb request %d"
|
||||
@ -273,20 +277,12 @@ void ctdb_recv_pkt(struct ctdb_context *ctdb, uint8_t *data, uint32_t length)
|
||||
hdr->srcnode, hdr->destnode,
|
||||
ctdb->vnn_map->generation,
|
||||
hdr->generation));
|
||||
break;
|
||||
}
|
||||
/* if we are in recovery mode we discard all traffic
|
||||
until the cluster has recovered.
|
||||
*/
|
||||
if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
|
||||
DEBUG(0,(__location__ " ctdb request %d"
|
||||
" length %d from node %d to %d"
|
||||
" while we are in recovery mode\n",
|
||||
hdr->reqid, hdr->length,
|
||||
hdr->srcnode, hdr->destnode));
|
||||
break;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
switch (hdr->operation) {
|
||||
case CTDB_REQ_CALL:
|
||||
ctdb->status.node.req_call++;
|
||||
ctdb_request_call(ctdb, hdr);
|
||||
break;
|
||||
@ -302,63 +298,11 @@ void ctdb_recv_pkt(struct ctdb_context *ctdb, uint8_t *data, uint32_t length)
|
||||
break;
|
||||
|
||||
case CTDB_REQ_DMASTER:
|
||||
/* verify that the remote node that sent us dmaster req
|
||||
is running in the same generation instance as this node
|
||||
*/
|
||||
if (ctdb->vnn_map->generation != hdr->generation) {
|
||||
DEBUG(0,(__location__ " ctdb dmaster request %d"
|
||||
" length %d from node %d to %d had an"
|
||||
" invalid generation id:%d while our"
|
||||
" generation id is:%d\n",
|
||||
hdr->reqid, hdr->length,
|
||||
hdr->srcnode, hdr->destnode,
|
||||
ctdb->vnn_map->generation,
|
||||
hdr->generation));
|
||||
break;
|
||||
}
|
||||
/* if we are in recovery mode we discard all traffic
|
||||
until the cluster has recovered.
|
||||
*/
|
||||
if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
|
||||
DEBUG(0,(__location__ " ctdb dmaster request %d"
|
||||
" length %d from node %d to %d"
|
||||
" while we are in recovery mode\n",
|
||||
hdr->reqid, hdr->length,
|
||||
hdr->srcnode, hdr->destnode));
|
||||
break;
|
||||
}
|
||||
|
||||
ctdb->status.node.req_dmaster++;
|
||||
ctdb_request_dmaster(ctdb, hdr);
|
||||
break;
|
||||
|
||||
case CTDB_REPLY_DMASTER:
|
||||
/* verify that the remote node that sent us dmaster reply
|
||||
is running in the same generation instance as this node
|
||||
*/
|
||||
if (ctdb->vnn_map->generation != hdr->generation) {
|
||||
DEBUG(0,(__location__ " ctdb dmaster reply %d"
|
||||
" length %d from node %d to %d had an"
|
||||
" invalid generation id:%d while our"
|
||||
" generation id is:%d\n",
|
||||
hdr->reqid, hdr->length,
|
||||
hdr->srcnode, hdr->destnode,
|
||||
ctdb->vnn_map->generation,
|
||||
hdr->generation));
|
||||
break;
|
||||
}
|
||||
/* if we are in recovery mode we discard all traffic
|
||||
until the cluster has recovered.
|
||||
*/
|
||||
if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
|
||||
DEBUG(0,(__location__ " ctdb dmaster reply %d "
|
||||
" length %d from node %d to %d"
|
||||
" while we are in recovery mode\n",
|
||||
hdr->reqid, hdr->length,
|
||||
hdr->srcnode, hdr->destnode));
|
||||
break;
|
||||
}
|
||||
|
||||
ctdb->status.node.reply_dmaster++;
|
||||
ctdb_reply_dmaster(ctdb, hdr);
|
||||
break;
|
||||
|
@ -363,7 +363,7 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
|
||||
|
||||
/* fetch the current record */
|
||||
ret = ctdb_ltdb_lock_fetch_requeue(ctdb_db, key, &header, hdr, &data2,
|
||||
ctdb_recv_raw_pkt, ctdb);
|
||||
ctdb_recv_raw_pkt, ctdb, False);
|
||||
if (ret == -1) {
|
||||
ctdb_fatal(ctdb, "ctdb_req_dmaster failed to fetch record");
|
||||
return;
|
||||
@ -390,6 +390,9 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
|
||||
return;
|
||||
}
|
||||
|
||||
/* use the rsn from the sending node */
|
||||
header.rsn = c->rsn;
|
||||
|
||||
/* check if the new dmaster is the lmaster, in which case we
|
||||
skip the dmaster reply */
|
||||
if (c->dmaster == ctdb->vnn) {
|
||||
@ -433,7 +436,7 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
|
||||
if the call will be answered locally */
|
||||
|
||||
ret = ctdb_ltdb_lock_fetch_requeue(ctdb_db, call.key, &header, hdr, &data,
|
||||
ctdb_recv_raw_pkt, ctdb);
|
||||
ctdb_recv_raw_pkt, ctdb, False);
|
||||
if (ret == -1) {
|
||||
ctdb_send_error(ctdb, hdr, ret, "ltdb fetch failed in ctdb_request_call");
|
||||
return;
|
||||
@ -556,7 +559,7 @@ void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
|
||||
data.dsize = c->datalen;
|
||||
|
||||
ret = ctdb_ltdb_lock_requeue(ctdb_db, key, hdr,
|
||||
ctdb_recv_raw_pkt, ctdb);
|
||||
ctdb_recv_raw_pkt, ctdb, False);
|
||||
if (ret == -2) {
|
||||
return;
|
||||
}
|
||||
@ -649,6 +652,7 @@ static void ctdb_call_timeout(struct event_context *ev, struct timed_event *te,
|
||||
state->c->hdr.destnode = ctdb->vnn;
|
||||
|
||||
ctdb_queue_packet(ctdb, &state->c->hdr);
|
||||
DEBUG(0,("requeued ctdb_call after timeout\n"));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -380,7 +380,7 @@ int ctdb_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
|
||||
int32_t status;
|
||||
|
||||
res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_REGISTER_SRVID, 0,
|
||||
tdb_null, NULL, NULL, &status, NULL);
|
||||
tdb_null, NULL, NULL, &status, NULL, NULL);
|
||||
if (res != 0 || status != 0) {
|
||||
DEBUG(0,("Failed to register srvid %llu\n", (unsigned long long)srvid));
|
||||
return -1;
|
||||
@ -399,7 +399,7 @@ int ctdb_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void
|
||||
int32_t status;
|
||||
|
||||
res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_DEREGISTER_SRVID, 0,
|
||||
tdb_null, NULL, NULL, &status, NULL);
|
||||
tdb_null, NULL, NULL, &status, NULL, NULL);
|
||||
if (res != 0 || status != 0) {
|
||||
DEBUG(0,("Failed to deregister srvid %llu\n", (unsigned long long)srvid));
|
||||
return -1;
|
||||
@ -620,6 +620,7 @@ struct ctdb_client_control_state {
|
||||
int32_t status;
|
||||
TDB_DATA outdata;
|
||||
enum call_state state;
|
||||
char *errormsg;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -649,6 +650,11 @@ static void ctdb_client_reply_control(struct ctdb_context *ctdb,
|
||||
state->outdata.dptr = c->data;
|
||||
state->outdata.dsize = c->datalen;
|
||||
state->status = c->status;
|
||||
if (c->errorlen) {
|
||||
state->errormsg = talloc_strndup(state,
|
||||
(char *)&c->data[c->datalen],
|
||||
c->errorlen);
|
||||
}
|
||||
|
||||
talloc_steal(state, c);
|
||||
|
||||
@ -682,7 +688,8 @@ static int ctdb_control_destructor(struct ctdb_client_control_state *state)
|
||||
int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid,
|
||||
uint32_t opcode, uint32_t flags, TDB_DATA data,
|
||||
TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status,
|
||||
struct timeval *timeout)
|
||||
struct timeval *timeout,
|
||||
char **errormsg)
|
||||
{
|
||||
struct ctdb_client_control_state *state;
|
||||
struct ctdb_req_control *c;
|
||||
@ -690,6 +697,10 @@ int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid,
|
||||
int ret;
|
||||
uint32_t timed_out;
|
||||
|
||||
if (errormsg) {
|
||||
*errormsg = NULL;
|
||||
}
|
||||
|
||||
/* if the domain socket is not yet open, open it */
|
||||
if (ctdb->daemon.sd==-1) {
|
||||
ctdb_socket_connect(ctdb);
|
||||
@ -701,6 +712,7 @@ int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid,
|
||||
state->ctdb = ctdb;
|
||||
state->reqid = ctdb_reqid_new(ctdb, state);
|
||||
state->state = CTDB_CALL_WAIT;
|
||||
state->errormsg = NULL;
|
||||
|
||||
talloc_set_destructor(state, ctdb_control_destructor);
|
||||
|
||||
@ -753,6 +765,14 @@ int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid,
|
||||
|
||||
*status = state->status;
|
||||
|
||||
if (!errormsg && state->errormsg) {
|
||||
DEBUG(0,("ctdb_control error: '%s'\n", state->errormsg));
|
||||
}
|
||||
|
||||
if (errormsg && state->errormsg) {
|
||||
(*errormsg) = talloc_move(mem_ctx, &state->errormsg);
|
||||
}
|
||||
|
||||
talloc_free(state);
|
||||
|
||||
return 0;
|
||||
@ -774,7 +794,7 @@ int ctdb_ctrl_process_exists(struct ctdb_context *ctdb, uint32_t destnode, pid_t
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_PROCESS_EXISTS, 0, data,
|
||||
NULL, NULL, &status, NULL);
|
||||
NULL, NULL, &status, NULL, NULL);
|
||||
if (ret != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for process_exists failed\n"));
|
||||
return -1;
|
||||
@ -795,7 +815,7 @@ int ctdb_ctrl_status(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_s
|
||||
ZERO_STRUCT(data);
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_STATUS, 0, data,
|
||||
ctdb, &data, &res, NULL);
|
||||
ctdb, &data, &res, NULL, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for status failed\n"));
|
||||
return -1;
|
||||
@ -826,7 +846,7 @@ int ctdb_ctrl_getvnnmap(struct ctdb_context *ctdb, struct timeval timeout, uint3
|
||||
ZERO_STRUCT(data);
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GETVNNMAP, 0, data,
|
||||
mem_ctx, &outdata, &res, &timeout);
|
||||
mem_ctx, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for getvnnmap failed\n"));
|
||||
return -1;
|
||||
@ -863,7 +883,7 @@ int ctdb_ctrl_getrecmode(struct ctdb_context *ctdb, struct timeval timeout, uint
|
||||
ZERO_STRUCT(data);
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GET_RECMODE, 0, data,
|
||||
ctdb, &outdata, &res, &timeout);
|
||||
ctdb, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for getrecmode failed\n"));
|
||||
return -1;
|
||||
@ -883,13 +903,12 @@ int ctdb_ctrl_setrecmode(struct ctdb_context *ctdb, struct timeval timeout, uint
|
||||
TDB_DATA data, outdata;
|
||||
int32_t res;
|
||||
|
||||
ZERO_STRUCT(data);
|
||||
data.dsize = sizeof(uint32_t);
|
||||
data.dptr = (unsigned char *)&recmode;
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_SET_RECMODE, 0, data,
|
||||
ctdb, &outdata, &res, &timeout);
|
||||
ctdb, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for setrecmode failed\n"));
|
||||
return -1;
|
||||
@ -910,7 +929,7 @@ int ctdb_ctrl_getrecmaster(struct ctdb_context *ctdb, struct timeval timeout, ui
|
||||
ZERO_STRUCT(data);
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GET_RECMASTER, 0, data,
|
||||
ctdb, &outdata, &res, &timeout);
|
||||
ctdb, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for getrecmaster failed\n"));
|
||||
return -1;
|
||||
@ -936,9 +955,9 @@ int ctdb_ctrl_setrecmaster(struct ctdb_context *ctdb, struct timeval timeout, ui
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_SET_RECMASTER, 0, data,
|
||||
ctdb, &outdata, &res, &timeout);
|
||||
ctdb, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for getrecmode failed\n"));
|
||||
DEBUG(0,(__location__ " ctdb_control for setrecmaster failed\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -958,7 +977,7 @@ int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, struct timeval timeout, uint32
|
||||
ZERO_STRUCT(data);
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GET_DBMAP, 0, data,
|
||||
mem_ctx, &outdata, &res, &timeout);
|
||||
mem_ctx, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for getdbmap failed\n"));
|
||||
return -1;
|
||||
@ -984,7 +1003,7 @@ int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb,
|
||||
ZERO_STRUCT(data);
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GET_NODEMAP, 0, data,
|
||||
mem_ctx, &outdata, &res, &timeout);
|
||||
mem_ctx, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for getnodes failed\n"));
|
||||
return -1;
|
||||
@ -1019,7 +1038,7 @@ int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb, struct timeval timeout, uint3
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_SETVNNMAP, 0, data,
|
||||
mem_ctx, &outdata, &res, &timeout);
|
||||
mem_ctx, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for setvnnmap failed\n"));
|
||||
return -1;
|
||||
@ -1050,7 +1069,7 @@ int ctdb_ctrl_pulldb(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_PULL_DB, 0, indata,
|
||||
mem_ctx, &outdata, &res, NULL);
|
||||
mem_ctx, &outdata, &res, NULL, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for pulldb failed\n"));
|
||||
return -1;
|
||||
@ -1106,7 +1125,7 @@ int ctdb_ctrl_copydb(struct ctdb_context *ctdb, struct timeval timeout, uint32_t
|
||||
|
||||
ret = ctdb_control(ctdb, sourcenode, 0,
|
||||
CTDB_CONTROL_PULL_DB, 0, indata,
|
||||
mem_ctx, &outdata, &res, &timeout);
|
||||
mem_ctx, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for pulldb failed\n"));
|
||||
return -1;
|
||||
@ -1114,7 +1133,7 @@ int ctdb_ctrl_copydb(struct ctdb_context *ctdb, struct timeval timeout, uint32_t
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_PUSH_DB, 0, outdata,
|
||||
mem_ctx, NULL, &res, &timeout);
|
||||
mem_ctx, NULL, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for pushdb failed\n"));
|
||||
return -1;
|
||||
@ -1140,7 +1159,7 @@ int ctdb_ctrl_setdmaster(struct ctdb_context *ctdb, struct timeval timeout, uint
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_SET_DMASTER, 0, indata,
|
||||
mem_ctx, &outdata, &res, &timeout);
|
||||
mem_ctx, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for setdmaster failed\n"));
|
||||
return -1;
|
||||
@ -1165,7 +1184,7 @@ int ctdb_ctrl_cleardb(struct ctdb_context *ctdb, uint32_t destnode, TALLOC_CTX *
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_CLEAR_DB, 0, indata,
|
||||
mem_ctx, &outdata, &res, NULL);
|
||||
mem_ctx, &outdata, &res, NULL, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for cleardb failed\n"));
|
||||
return -1;
|
||||
@ -1210,7 +1229,7 @@ int ctdb_ctrl_ping(struct ctdb_context *ctdb, uint32_t destnode)
|
||||
|
||||
ZERO_STRUCT(data);
|
||||
ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_PING, 0,
|
||||
data, NULL, NULL, &res, NULL);
|
||||
data, NULL, NULL, &res, NULL, NULL);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -1229,7 +1248,7 @@ int ctdb_ctrl_get_config(struct ctdb_context *ctdb)
|
||||
|
||||
ZERO_STRUCT(data);
|
||||
ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_CONFIG, 0,
|
||||
data, ctdb, &data, &res, NULL);
|
||||
data, ctdb, &data, &res, NULL, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -1264,7 +1283,7 @@ int ctdb_ctrl_getdbpath(struct ctdb_context *ctdb, struct timeval timeout, uint3
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GETDBPATH, 0, data,
|
||||
mem_ctx, &data, &res, &timeout);
|
||||
mem_ctx, &data, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -1294,7 +1313,7 @@ int ctdb_ctrl_getdbname(struct ctdb_context *ctdb, struct timeval timeout, uint3
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GET_DBNAME, 0, data,
|
||||
mem_ctx, &data, &res, &timeout);
|
||||
mem_ctx, &data, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -1323,7 +1342,7 @@ int ctdb_ctrl_createdb(struct ctdb_context *ctdb, struct timeval timeout, uint32
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_DB_ATTACH, 0, data,
|
||||
mem_ctx, &data, &res, &timeout);
|
||||
mem_ctx, &data, &res, &timeout, NULL);
|
||||
|
||||
if (ret != 0 || res != 0) {
|
||||
return -1;
|
||||
@ -1343,7 +1362,7 @@ int ctdb_ctrl_get_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, uint3
|
||||
|
||||
ZERO_STRUCT(data);
|
||||
ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DEBUG, 0, data,
|
||||
ctdb, &data, &res, NULL);
|
||||
ctdb, &data, &res, NULL, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -1370,7 +1389,7 @@ int ctdb_ctrl_set_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, uint3
|
||||
data.dsize = sizeof(level);
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_DEBUG, 0, data,
|
||||
NULL, NULL, &res, NULL);
|
||||
NULL, NULL, &res, NULL, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -1425,7 +1444,7 @@ int ctdb_status_reset(struct ctdb_context *ctdb, uint32_t destnode)
|
||||
ZERO_STRUCT(data);
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_STATUS_RESET, 0, data,
|
||||
NULL, NULL, &res, NULL);
|
||||
NULL, NULL, &res, NULL, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for reset status failed\n"));
|
||||
return -1;
|
||||
@ -1456,7 +1475,7 @@ struct ctdb_db_context *ctdb_attach(struct ctdb_context *ctdb, const char *name)
|
||||
|
||||
/* tell ctdb daemon to attach */
|
||||
ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_DB_ATTACH,
|
||||
0, data, ctdb_db, &data, &res, NULL);
|
||||
0, data, ctdb_db, &data, &res, NULL, NULL);
|
||||
if (ret != 0 || res != 0 || data.dsize != sizeof(uint32_t)) {
|
||||
DEBUG(0,("Failed to attach to database '%s'\n", name));
|
||||
talloc_free(ctdb_db);
|
||||
@ -1504,7 +1523,7 @@ int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id)
|
||||
data.dsize = sizeof(c);
|
||||
|
||||
ret = ctdb_control(ctdb_db->ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_SET_CALL, 0,
|
||||
data, NULL, NULL, &status, NULL);
|
||||
data, NULL, NULL, &status, NULL, NULL);
|
||||
if (ret != 0 || status != 0) {
|
||||
DEBUG(0,("ctdb_set_call failed for call %u\n", id));
|
||||
return -1;
|
||||
@ -1594,7 +1613,7 @@ int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *
|
||||
data.dsize = sizeof(t);
|
||||
|
||||
ret = ctdb_control(ctdb_db->ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_TRAVERSE_START, 0,
|
||||
data, NULL, NULL, &status, NULL);
|
||||
data, NULL, NULL, &status, NULL, NULL);
|
||||
if (ret != 0 || status != 0) {
|
||||
DEBUG(0,("ctdb_traverse_all failed\n"));
|
||||
ctdb_remove_message_handler(ctdb_db->ctdb, srvid, &state);
|
||||
@ -1655,7 +1674,7 @@ int ctdb_ctrl_getpid(struct ctdb_context *ctdb, struct timeval timeout, uint32_t
|
||||
ZERO_STRUCT(data);
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GET_PID, 0, data,
|
||||
ctdb, &outdata, &res, &timeout);
|
||||
ctdb, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for getpid failed\n"));
|
||||
return -1;
|
||||
@ -1666,3 +1685,41 @@ int ctdb_ctrl_getpid(struct ctdb_context *ctdb, struct timeval timeout, uint32_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
freeze a node
|
||||
*/
|
||||
int ctdb_ctrl_freeze(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
|
||||
{
|
||||
int ret;
|
||||
int32_t res;
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_FREEZE, 0, tdb_null,
|
||||
NULL, NULL, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control freeze failed\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
thaw a node
|
||||
*/
|
||||
int ctdb_ctrl_thaw(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
|
||||
{
|
||||
int ret;
|
||||
int32_t res;
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_THAW, 0, tdb_null,
|
||||
NULL, NULL, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control thaw failed\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -38,11 +38,16 @@ struct ctdb_control_state {
|
||||
process a control request
|
||||
*/
|
||||
static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
|
||||
uint32_t opcode,
|
||||
uint64_t srvid, uint32_t client_id,
|
||||
struct ctdb_req_control *c,
|
||||
TDB_DATA indata,
|
||||
TDB_DATA *outdata, uint32_t srcnode)
|
||||
TDB_DATA *outdata, uint32_t srcnode,
|
||||
const char **errormsg,
|
||||
bool *async_reply)
|
||||
{
|
||||
uint32_t opcode = c->opcode;
|
||||
uint64_t srvid = c->srvid;
|
||||
uint32_t client_id = c->client_id;
|
||||
|
||||
switch (opcode) {
|
||||
case CTDB_CONTROL_PROCESS_EXISTS: {
|
||||
CHECK_CONTROL_DATA_SIZE(sizeof(pid_t));
|
||||
@ -67,6 +72,8 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
|
||||
CHECK_CONTROL_DATA_SIZE(0);
|
||||
ctdb->status.controls.status++;
|
||||
ctdb->status.memory_used = talloc_total_size(ctdb);
|
||||
ctdb->status.frozen = (ctdb->freeze_mode == CTDB_FREEZE_FROZEN);
|
||||
ctdb->status.recovering = (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE);
|
||||
outdata->dptr = (uint8_t *)&ctdb->status;
|
||||
outdata->dsize = sizeof(ctdb->status);
|
||||
return 0;
|
||||
@ -115,11 +122,6 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
|
||||
case CTDB_CONTROL_PUSH_DB:
|
||||
return ctdb_control_push_db(ctdb, indata);
|
||||
|
||||
case CTDB_CONTROL_SET_RECMODE: {
|
||||
ctdb->recovery_mode = ((uint32_t *)(&indata.dptr[0]))[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
case CTDB_CONTROL_GET_RECMODE: {
|
||||
return ctdb->recovery_mode;
|
||||
}
|
||||
@ -225,12 +227,63 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
|
||||
CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
|
||||
return ctdb_ltdb_set_seqnum_frequency(ctdb, *(uint32_t *)indata.dptr);
|
||||
|
||||
case CTDB_CONTROL_FREEZE:
|
||||
CHECK_CONTROL_DATA_SIZE(0);
|
||||
return ctdb_control_freeze(ctdb, c, async_reply);
|
||||
|
||||
case CTDB_CONTROL_THAW:
|
||||
CHECK_CONTROL_DATA_SIZE(0);
|
||||
return ctdb_control_thaw(ctdb);
|
||||
|
||||
case CTDB_CONTROL_SET_RECMODE:
|
||||
CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
|
||||
return ctdb_control_set_recmode(ctdb, indata, errormsg);
|
||||
|
||||
default:
|
||||
DEBUG(0,(__location__ " Unknown CTDB control opcode %u\n", opcode));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
send a reply for a ctdb control
|
||||
*/
|
||||
void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_control *c,
|
||||
TDB_DATA *outdata, int32_t status, const char *errormsg)
|
||||
{
|
||||
struct ctdb_reply_control *r;
|
||||
size_t len;
|
||||
|
||||
/* some controls send no reply */
|
||||
if (c->flags & CTDB_CTRL_FLAG_NOREPLY) {
|
||||
return;
|
||||
}
|
||||
|
||||
len = offsetof(struct ctdb_reply_control, data) + (outdata?outdata->dsize:0);
|
||||
if (errormsg) {
|
||||
len += strlen(errormsg);
|
||||
}
|
||||
r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CONTROL, len, struct ctdb_reply_control);
|
||||
CTDB_NO_MEMORY_VOID(ctdb, r);
|
||||
|
||||
r->hdr.destnode = c->hdr.srcnode;
|
||||
r->hdr.reqid = c->hdr.reqid;
|
||||
r->status = status;
|
||||
r->datalen = outdata?outdata->dsize:0;
|
||||
if (outdata && outdata->dsize) {
|
||||
memcpy(&r->data[0], outdata->dptr, outdata->dsize);
|
||||
}
|
||||
if (errormsg) {
|
||||
r->errorlen = strlen(errormsg);
|
||||
memcpy(&r->data[r->datalen], errormsg, r->errorlen);
|
||||
}
|
||||
|
||||
ctdb_queue_packet(ctdb, &r->hdr);
|
||||
|
||||
talloc_free(r);
|
||||
}
|
||||
|
||||
/*
|
||||
called when a CTDB_REQ_CONTROL packet comes in
|
||||
*/
|
||||
@ -238,37 +291,21 @@ void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
|
||||
{
|
||||
struct ctdb_req_control *c = (struct ctdb_req_control *)hdr;
|
||||
TDB_DATA data, *outdata;
|
||||
struct ctdb_reply_control *r;
|
||||
int32_t status;
|
||||
size_t len;
|
||||
bool async_reply = False;
|
||||
const char *errormsg = NULL;
|
||||
|
||||
data.dptr = &c->data[0];
|
||||
data.dsize = c->datalen;
|
||||
|
||||
outdata = talloc_zero(c, TDB_DATA);
|
||||
status = ctdb_control_dispatch(ctdb, c->opcode, c->srvid, c->client_id,
|
||||
data, outdata, hdr->srcnode);
|
||||
|
||||
/* some controls send no reply */
|
||||
if (c->flags & CTDB_CTRL_FLAG_NOREPLY) {
|
||||
return;
|
||||
status = ctdb_control_dispatch(ctdb, c, data, outdata, hdr->srcnode,
|
||||
&errormsg, &async_reply);
|
||||
|
||||
if (!async_reply) {
|
||||
ctdb_request_control_reply(ctdb, c, outdata, status, errormsg);
|
||||
}
|
||||
|
||||
len = offsetof(struct ctdb_reply_control, data) + outdata->dsize;
|
||||
r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CONTROL, len, struct ctdb_reply_control);
|
||||
CTDB_NO_MEMORY_VOID(ctdb, r);
|
||||
|
||||
r->hdr.destnode = hdr->srcnode;
|
||||
r->hdr.reqid = hdr->reqid;
|
||||
r->status = status;
|
||||
r->datalen = outdata->dsize;
|
||||
if (outdata->dsize) {
|
||||
memcpy(&r->data[0], outdata->dptr, outdata->dsize);
|
||||
}
|
||||
|
||||
ctdb_queue_packet(ctdb, &r->hdr);
|
||||
|
||||
talloc_free(r);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -279,6 +316,7 @@ void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
|
||||
struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr;
|
||||
TDB_DATA data;
|
||||
struct ctdb_control_state *state;
|
||||
const char *errormsg = NULL;
|
||||
|
||||
state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_control_state);
|
||||
if (state == NULL) {
|
||||
@ -295,12 +333,16 @@ void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
|
||||
|
||||
data.dptr = &c->data[0];
|
||||
data.dsize = c->datalen;
|
||||
if (c->errorlen) {
|
||||
errormsg = talloc_strndup(state,
|
||||
(char *)&c->data[c->datalen], c->errorlen);
|
||||
}
|
||||
|
||||
/* make state a child of the packet, so it goes away when the packet
|
||||
is freed. */
|
||||
talloc_steal(hdr, state);
|
||||
|
||||
state->callback(ctdb, c->status, data, state->private_data);
|
||||
state->callback(ctdb, c->status, data, errormsg, state->private_data);
|
||||
}
|
||||
|
||||
static int ctdb_control_destructor(struct ctdb_control_state *state)
|
||||
@ -316,11 +358,15 @@ static void ctdb_control_timeout(struct event_context *ev, struct timed_event *t
|
||||
struct timeval t, void *private_data)
|
||||
{
|
||||
struct ctdb_control_state *state = talloc_get_type(private_data, struct ctdb_control_state);
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(ev);
|
||||
|
||||
state->ctdb->status.timeouts.control++;
|
||||
|
||||
state->callback(state->ctdb, -1, tdb_null, state->private_data);
|
||||
talloc_free(state);
|
||||
talloc_steal(tmp_ctx, state);
|
||||
|
||||
state->callback(state->ctdb, -1, tdb_null, "ctdb_control timed out",
|
||||
state->private_data);
|
||||
talloc_free(tmp_ctx);
|
||||
}
|
||||
|
||||
|
||||
|
@ -326,7 +326,7 @@ static void daemon_call_from_client_callback(struct ctdb_call_state *state)
|
||||
|
||||
res = daemon_queue_send(client, &r->hdr);
|
||||
if (res != 0) {
|
||||
DEBUG(0, (__location__ "Failed to queue packet from daemon to client\n"));
|
||||
DEBUG(0, (__location__ " Failed to queue packet from daemon to client\n"));
|
||||
}
|
||||
ctdb_latency(&client->ctdb->status.max_call_latency, dstate->start_time);
|
||||
talloc_free(dstate);
|
||||
@ -334,30 +334,9 @@ static void daemon_call_from_client_callback(struct ctdb_call_state *state)
|
||||
}
|
||||
|
||||
|
||||
struct ctdb_client_retry {
|
||||
struct ctdb_client *client;
|
||||
struct ctdb_req_call *call;
|
||||
};
|
||||
|
||||
static void daemon_request_call_from_client(struct ctdb_client *client,
|
||||
struct ctdb_req_call *c);
|
||||
|
||||
/*
|
||||
triggered after a one second delay, retrying a client packet
|
||||
that was deferred because of the daemon being in recovery mode
|
||||
*/
|
||||
static void retry_client_packet(struct event_context *ev, struct timed_event *te,
|
||||
struct timeval t, void *private_data)
|
||||
{
|
||||
struct ctdb_client_retry *retry = talloc_get_type(private_data, struct ctdb_client_retry);
|
||||
|
||||
daemon_request_call_from_client(retry->client, retry->call);
|
||||
|
||||
talloc_free(retry);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
this is called when the ctdb daemon received a ctdb request call
|
||||
from a local client over the unix domain socket
|
||||
@ -374,29 +353,6 @@ static void daemon_request_call_from_client(struct ctdb_client *client,
|
||||
int ret;
|
||||
struct ctdb_context *ctdb = client->ctdb;
|
||||
|
||||
if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
|
||||
struct ctdb_client_retry *retry;
|
||||
|
||||
DEBUG(0,(__location__ " ctdb call %u from client"
|
||||
" while we are in recovery mode. Deferring it\n",
|
||||
c->hdr.reqid));
|
||||
|
||||
/* hang the event and the structure off client */
|
||||
retry = talloc(client, struct ctdb_client_retry);
|
||||
CTDB_NO_MEMORY_VOID(ctdb, retry);
|
||||
retry->client = client;
|
||||
retry->call = c;
|
||||
|
||||
/* this ensures that after the retry happens we
|
||||
eventually free this request */
|
||||
talloc_steal(retry, c);
|
||||
|
||||
event_add_timed(ctdb->ev, retry, timeval_current_ofs(1,0), retry_client_packet, retry);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ctdb->status.total_calls++;
|
||||
ctdb->status.pending_calls++;
|
||||
|
||||
@ -413,7 +369,7 @@ static void daemon_request_call_from_client(struct ctdb_client *client,
|
||||
|
||||
ret = ctdb_ltdb_lock_fetch_requeue(ctdb_db, key, &header,
|
||||
(struct ctdb_req_header *)c, &data,
|
||||
daemon_incoming_packet, client);
|
||||
daemon_incoming_packet, client, True);
|
||||
if (ret == -2) {
|
||||
/* will retry later */
|
||||
ctdb->status.pending_calls--;
|
||||
@ -644,10 +600,15 @@ static int ux_socket_bind(struct ctdb_context *ctdb)
|
||||
|
||||
ctdb->daemon.sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (ctdb->daemon.sd == -1) {
|
||||
ctdb->daemon.sd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fchown(ctdb->daemon.sd, geteuid(), getegid()) != 0 ||
|
||||
fchmod(ctdb->daemon.sd, 0700) != 0) {
|
||||
DEBUG(0,("Unable to secure ctdb socket '%s', ctdb->daemon.name\n"));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
set_non_blocking(ctdb->daemon.sd);
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
@ -655,13 +616,20 @@ static int ux_socket_bind(struct ctdb_context *ctdb)
|
||||
strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path));
|
||||
|
||||
if (bind(ctdb->daemon.sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
close(ctdb->daemon.sd);
|
||||
ctdb->daemon.sd = -1;
|
||||
return -1;
|
||||
DEBUG(0,("Unable to bind on ctdb socket '%s', ctdb->daemon.name\n"));
|
||||
goto failed;
|
||||
}
|
||||
listen(ctdb->daemon.sd, 1);
|
||||
if (listen(ctdb->daemon.sd, 10) != 0) {
|
||||
DEBUG(0,("Unable to listen on ctdb socket '%s', ctdb->daemon.name\n"));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
close(ctdb->daemon.sd);
|
||||
ctdb->daemon.sd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -869,6 +837,7 @@ struct daemon_control_state {
|
||||
*/
|
||||
static void daemon_control_callback(struct ctdb_context *ctdb,
|
||||
uint32_t status, TDB_DATA data,
|
||||
const char *errormsg,
|
||||
void *private_data)
|
||||
{
|
||||
struct daemon_control_state *state = talloc_get_type(private_data,
|
||||
@ -879,6 +848,9 @@ static void daemon_control_callback(struct ctdb_context *ctdb,
|
||||
|
||||
/* construct a message to send to the client containing the data */
|
||||
len = offsetof(struct ctdb_reply_control, data) + data.dsize;
|
||||
if (errormsg) {
|
||||
len += strlen(errormsg);
|
||||
}
|
||||
r = ctdbd_allocate_pkt(ctdb, state, CTDB_REPLY_CONTROL, len,
|
||||
struct ctdb_reply_control);
|
||||
CTDB_NO_MEMORY_VOID(ctdb, r);
|
||||
@ -886,7 +858,12 @@ static void daemon_control_callback(struct ctdb_context *ctdb,
|
||||
r->hdr.reqid = state->reqid;
|
||||
r->status = status;
|
||||
r->datalen = data.dsize;
|
||||
r->errorlen = 0;
|
||||
memcpy(&r->data[0], data.dptr, data.dsize);
|
||||
if (errormsg) {
|
||||
r->errorlen = strlen(errormsg);
|
||||
memcpy(&r->data[r->datalen], errormsg, r->errorlen);
|
||||
}
|
||||
|
||||
daemon_queue_send(client, &r->hdr);
|
||||
|
||||
|
227
ctdb/common/ctdb_freeze.c
Normal file
227
ctdb/common/ctdb_freeze.c
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
ctdb freeze handling
|
||||
|
||||
Copyright (C) Andrew Tridgell 2007
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "includes.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "lib/tdb/include/tdb.h"
|
||||
#include "system/network.h"
|
||||
#include "system/filesys.h"
|
||||
#include "system/wait.h"
|
||||
#include "../include/ctdb_private.h"
|
||||
#include "lib/util/dlinklist.h"
|
||||
#include "db_wrap.h"
|
||||
|
||||
|
||||
/*
|
||||
lock all databases
|
||||
*/
|
||||
static int ctdb_lock_all_databases(struct ctdb_context *ctdb)
|
||||
{
|
||||
struct ctdb_db_context *ctdb_db;
|
||||
for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
|
||||
if (tdb_lockall(ctdb_db->ltdb->tdb) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
a list of control requests waiting for a freeze lock child to get
|
||||
the database locks
|
||||
*/
|
||||
struct ctdb_freeze_waiter {
|
||||
struct ctdb_freeze_waiter *next, *prev;
|
||||
struct ctdb_context *ctdb;
|
||||
struct ctdb_req_control *c;
|
||||
int32_t status;
|
||||
};
|
||||
|
||||
/* a handle to a freeze lock child process */
|
||||
struct ctdb_freeze_handle {
|
||||
struct ctdb_context *ctdb;
|
||||
pid_t child;
|
||||
int fd;
|
||||
struct ctdb_freeze_waiter *waiters;
|
||||
};
|
||||
|
||||
/*
|
||||
destroy a freeze handle
|
||||
*/
|
||||
static int ctdb_freeze_handle_destructor(struct ctdb_freeze_handle *h)
|
||||
{
|
||||
h->ctdb->freeze_mode = CTDB_FREEZE_NONE;
|
||||
kill(h->child, SIGKILL);
|
||||
waitpid(h->child, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
called when the child writes its status to us
|
||||
*/
|
||||
static void ctdb_freeze_lock_handler(struct event_context *ev, struct fd_event *fde,
|
||||
uint16_t flags, void *private_data)
|
||||
{
|
||||
struct ctdb_freeze_handle *h = talloc_get_type(private_data, struct ctdb_freeze_handle);
|
||||
int32_t status;
|
||||
struct ctdb_freeze_waiter *w;
|
||||
|
||||
if (h->ctdb->freeze_mode == CTDB_FREEZE_FROZEN) {
|
||||
DEBUG(0,("freeze child died - unfreezing\n"));
|
||||
talloc_free(h);
|
||||
return;
|
||||
}
|
||||
|
||||
if (read(h->fd, &status, sizeof(status)) != sizeof(status)) {
|
||||
DEBUG(0,("read error from freeze lock child\n"));
|
||||
status = -1;
|
||||
}
|
||||
|
||||
if (status == -1) {
|
||||
DEBUG(0,("Failed to get locks in ctdb_freeze_child\n"));
|
||||
/* we didn't get the locks - destroy the handle */
|
||||
talloc_free(h);
|
||||
return;
|
||||
}
|
||||
|
||||
h->ctdb->freeze_mode = CTDB_FREEZE_FROZEN;
|
||||
|
||||
/* notify the waiters */
|
||||
while ((w = h->ctdb->freeze_handle->waiters)) {
|
||||
w->status = status;
|
||||
DLIST_REMOVE(h->ctdb->freeze_handle->waiters, w);
|
||||
talloc_free(w);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
create a child which gets locks on all the open databases, then calls the callback telling the parent
|
||||
that it is done
|
||||
*/
|
||||
static struct ctdb_freeze_handle *ctdb_freeze_lock(struct ctdb_context *ctdb)
|
||||
{
|
||||
struct ctdb_freeze_handle *h;
|
||||
int fd[2];
|
||||
struct fd_event *fde;
|
||||
|
||||
h = talloc_zero(ctdb, struct ctdb_freeze_handle);
|
||||
CTDB_NO_MEMORY_VOID(ctdb, h);
|
||||
|
||||
h->ctdb = ctdb;
|
||||
|
||||
/* use socketpair() instead of pipe() so we have bi-directional fds */
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0) {
|
||||
DEBUG(0,("Failed to create pipe for ctdb_freeze_lock\n"));
|
||||
talloc_free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
h->child = fork();
|
||||
if (h->child == -1) {
|
||||
DEBUG(0,("Failed to fork child for ctdb_freeze_lock\n"));
|
||||
talloc_free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (h->child == 0) {
|
||||
int ret;
|
||||
/* in the child */
|
||||
close(fd[0]);
|
||||
ret = ctdb_lock_all_databases(ctdb);
|
||||
if (ret != 0) {
|
||||
_exit(0);
|
||||
}
|
||||
write(fd[1], &ret, sizeof(ret));
|
||||
/* the read here means we will die if the parent exits */
|
||||
read(fd[1], &ret, sizeof(ret));
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
talloc_set_destructor(h, ctdb_freeze_handle_destructor);
|
||||
|
||||
close(fd[1]);
|
||||
|
||||
h->fd = fd[0];
|
||||
|
||||
fde = event_add_fd(ctdb->ev, h, h->fd, EVENT_FD_READ|EVENT_FD_AUTOCLOSE,
|
||||
ctdb_freeze_lock_handler, h);
|
||||
if (fde == NULL) {
|
||||
DEBUG(0,("Failed to setup fd event for ctdb_freeze_lock\n"));
|
||||
close(fd[0]);
|
||||
talloc_free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/*
|
||||
destroy a waiter for a freeze mode change
|
||||
*/
|
||||
static int ctdb_freeze_waiter_destructor(struct ctdb_freeze_waiter *w)
|
||||
{
|
||||
DLIST_REMOVE(w->ctdb->freeze_handle->waiters, w);
|
||||
ctdb_request_control_reply(w->ctdb, w->c, NULL, w->status, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
freeze the databases
|
||||
*/
|
||||
int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply)
|
||||
{
|
||||
struct ctdb_freeze_waiter *w;
|
||||
|
||||
if (ctdb->freeze_mode == CTDB_FREEZE_FROZEN) {
|
||||
/* we're already frozen */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if there isn't a freeze lock child then create one */
|
||||
if (!ctdb->freeze_handle) {
|
||||
ctdb->freeze_handle = ctdb_freeze_lock(ctdb);
|
||||
CTDB_NO_MEMORY(ctdb, ctdb->freeze_handle);
|
||||
ctdb->freeze_mode = CTDB_FREEZE_PENDING;
|
||||
}
|
||||
|
||||
/* add ourselves to list of waiters */
|
||||
w = talloc(ctdb->freeze_handle, struct ctdb_freeze_waiter);
|
||||
CTDB_NO_MEMORY(ctdb, w);
|
||||
w->ctdb = ctdb;
|
||||
w->c = talloc_steal(w, c);
|
||||
w->status = -1;
|
||||
talloc_set_destructor(w, ctdb_freeze_waiter_destructor);
|
||||
DLIST_ADD(ctdb->freeze_handle->waiters, w);
|
||||
|
||||
/* we won't reply till later */
|
||||
*async_reply = True;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
thaw the databases
|
||||
*/
|
||||
int32_t ctdb_control_thaw(struct ctdb_context *ctdb)
|
||||
{
|
||||
talloc_free(ctdb->freeze_handle);
|
||||
ctdb->freeze_handle = NULL;
|
||||
return 0;
|
||||
}
|
@ -195,6 +195,8 @@ struct lock_fetch_state {
|
||||
void (*recv_pkt)(void *, uint8_t *, uint32_t);
|
||||
void *recv_context;
|
||||
struct ctdb_req_header *hdr;
|
||||
uint32_t generation;
|
||||
bool ignore_generation;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -203,6 +205,12 @@ struct lock_fetch_state {
|
||||
static void lock_fetch_callback(void *p)
|
||||
{
|
||||
struct lock_fetch_state *state = talloc_get_type(p, struct lock_fetch_state);
|
||||
if (!state->ignore_generation &&
|
||||
state->generation != state->ctdb->vnn_map->generation) {
|
||||
DEBUG(0,("Discarding previous generation lockwait packet\n"));
|
||||
talloc_free(state->hdr);
|
||||
return;
|
||||
}
|
||||
state->recv_pkt(state->recv_context, (uint8_t *)state->hdr, state->hdr->length);
|
||||
DEBUG(2,(__location__ " PACKET REQUEUED\n"));
|
||||
}
|
||||
@ -235,7 +243,7 @@ static void lock_fetch_callback(void *p)
|
||||
int ctdb_ltdb_lock_requeue(struct ctdb_db_context *ctdb_db,
|
||||
TDB_DATA key, struct ctdb_req_header *hdr,
|
||||
void (*recv_pkt)(void *, uint8_t *, uint32_t ),
|
||||
void *recv_context)
|
||||
void *recv_context, bool ignore_generation)
|
||||
{
|
||||
int ret;
|
||||
struct tdb_context *tdb = ctdb_db->ltdb->tdb;
|
||||
@ -267,6 +275,8 @@ int ctdb_ltdb_lock_requeue(struct ctdb_db_context *ctdb_db,
|
||||
state->hdr = hdr;
|
||||
state->recv_pkt = recv_pkt;
|
||||
state->recv_context = recv_context;
|
||||
state->generation = ctdb_db->ctdb->vnn_map->generation;
|
||||
state->ignore_generation = ignore_generation;
|
||||
|
||||
/* now the contended path */
|
||||
h = ctdb_lockwait(ctdb_db, key, lock_fetch_callback, state);
|
||||
@ -291,11 +301,12 @@ int ctdb_ltdb_lock_fetch_requeue(struct ctdb_db_context *ctdb_db,
|
||||
TDB_DATA key, struct ctdb_ltdb_header *header,
|
||||
struct ctdb_req_header *hdr, TDB_DATA *data,
|
||||
void (*recv_pkt)(void *, uint8_t *, uint32_t ),
|
||||
void *recv_context)
|
||||
void *recv_context, bool ignore_generation)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ctdb_ltdb_lock_requeue(ctdb_db, key, hdr, recv_pkt, recv_context);
|
||||
ret = ctdb_ltdb_lock_requeue(ctdb_db, key, hdr, recv_pkt,
|
||||
recv_context, ignore_generation);
|
||||
if (ret == 0) {
|
||||
ret = ctdb_ltdb_fetch(ctdb_db, key, header, hdr, data);
|
||||
if (ret != 0) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
ctdb_control protocol code
|
||||
ctdb recovery code
|
||||
|
||||
Copyright (C) Andrew Tridgell 2007
|
||||
Copyright (C) Ronnie Sahlberg 2007
|
||||
@ -28,6 +28,43 @@
|
||||
#include "lib/util/dlinklist.h"
|
||||
#include "db_wrap.h"
|
||||
|
||||
/*
|
||||
lock all databases - mark only
|
||||
*/
|
||||
static int ctdb_lock_all_databases_mark(struct ctdb_context *ctdb)
|
||||
{
|
||||
struct ctdb_db_context *ctdb_db;
|
||||
if (ctdb->freeze_mode != CTDB_FREEZE_FROZEN) {
|
||||
DEBUG(0,("Attempt to mark all databases locked when not frozen\n"));
|
||||
return -1;
|
||||
}
|
||||
for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
|
||||
if (tdb_lockall_mark(ctdb_db->ltdb->tdb) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
lock all databases - unmark only
|
||||
*/
|
||||
static int ctdb_lock_all_databases_unmark(struct ctdb_context *ctdb)
|
||||
{
|
||||
struct ctdb_db_context *ctdb_db;
|
||||
if (ctdb->freeze_mode != CTDB_FREEZE_FROZEN) {
|
||||
DEBUG(0,("Attempt to unmark all databases locked when not frozen\n"));
|
||||
return -1;
|
||||
}
|
||||
for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
|
||||
if (tdb_lockall_unmark(ctdb_db->ltdb->tdb) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ctdb_control_getvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
|
||||
{
|
||||
@ -87,7 +124,7 @@ ctdb_control_getdbmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indat
|
||||
outdata->dsize = offsetof(struct ctdb_dbid_map, dbids) + 4*len;
|
||||
outdata->dptr = (unsigned char *)talloc_zero_size(outdata, outdata->dsize);
|
||||
if (!outdata->dptr) {
|
||||
DEBUG(0, (__location__ "Failed to allocate dbmap array\n"));
|
||||
DEBUG(0, (__location__ " Failed to allocate dbmap array\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -113,7 +150,7 @@ ctdb_control_getnodemap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA ind
|
||||
outdata->dsize = offsetof(struct ctdb_node_map, nodes) + num_nodes*sizeof(struct ctdb_node_and_flags);
|
||||
outdata->dptr = (unsigned char *)talloc_zero_size(outdata, outdata->dsize);
|
||||
if (!outdata->dptr) {
|
||||
DEBUG(0, (__location__ "Failed to allocate nodemap array\n"));
|
||||
DEBUG(0, (__location__ " Failed to allocate nodemap array\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -173,6 +210,11 @@ int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DAT
|
||||
int i;
|
||||
size_t len = 0;
|
||||
|
||||
if (ctdb->freeze_mode != CTDB_FREEZE_FROZEN) {
|
||||
DEBUG(0,("rejecting ctdb_control_pull_db when not frozen\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pull = (struct ctdb_control_pulldb *)indata.dptr;
|
||||
|
||||
ctdb_db = find_ctdb_db(ctdb, pull->db_id);
|
||||
@ -183,18 +225,19 @@ int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DAT
|
||||
|
||||
params.ctdb = ctdb;
|
||||
params.lmaster = pull->lmaster;
|
||||
|
||||
params.rec_count = 0;
|
||||
params.recs = talloc_array(outdata, struct getkeys_rec, 0);
|
||||
CTDB_NO_MEMORY(ctdb, params.recs);
|
||||
|
||||
if (tdb_lockall_nonblock(ctdb_db->ltdb->tdb) != 0) {
|
||||
DEBUG(0,(__location__ " Failed to get nonblock lock on entired db - failing\n"));
|
||||
if (ctdb_lock_all_databases_mark(ctdb) != 0) {
|
||||
DEBUG(0,(__location__ " Failed to get lock on entired db - failing\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
tdb_traverse_read(ctdb_db->ltdb->tdb, traverse_getkeys, ¶ms);
|
||||
|
||||
tdb_unlockall(ctdb_db->ltdb->tdb);
|
||||
ctdb_lock_all_databases_unmark(ctdb);
|
||||
|
||||
reply = talloc(outdata, struct ctdb_control_pulldb_reply);
|
||||
CTDB_NO_MEMORY(ctdb, reply);
|
||||
@ -231,6 +274,11 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
int i, ret;
|
||||
struct ctdb_rec_data *rec;
|
||||
|
||||
if (ctdb->freeze_mode != CTDB_FREEZE_FROZEN) {
|
||||
DEBUG(0,("rejecting ctdb_control_push_db when not frozen\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (indata.dsize < offsetof(struct ctdb_control_pulldb_reply, data)) {
|
||||
DEBUG(0,(__location__ " invalid data in pulldb reply\n"));
|
||||
return -1;
|
||||
@ -242,8 +290,8 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tdb_lockall_nonblock(ctdb_db->ltdb->tdb) != 0) {
|
||||
DEBUG(0,(__location__ " Failed to get nonblock lock on entired db - failing\n"));
|
||||
if (ctdb_lock_all_databases_mark(ctdb) != 0) {
|
||||
DEBUG(0,(__location__ " Failed to get lock on entired db - failing\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -260,8 +308,7 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
|
||||
if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
|
||||
DEBUG(0,(__location__ " bad ltdb record\n"));
|
||||
ctdb_ltdb_unlock(ctdb_db, key);
|
||||
return -1;
|
||||
goto failed;
|
||||
}
|
||||
hdr = (struct ctdb_ltdb_header *)data.dptr;
|
||||
data.dptr += sizeof(*hdr);
|
||||
@ -269,25 +316,29 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
|
||||
ret = ctdb_ltdb_fetch(ctdb_db, key, &header, NULL, NULL);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to fetch record\n"));
|
||||
tdb_unlockall(ctdb_db->ltdb->tdb);
|
||||
return -1;
|
||||
DEBUG(0, (__location__ " Unable to fetch record\n"));
|
||||
goto failed;
|
||||
}
|
||||
if (header.rsn < hdr->rsn) {
|
||||
/* The check for dmaster gives priority to the dmaster
|
||||
if the rsn values are equal */
|
||||
if (header.rsn < hdr->rsn ||
|
||||
(header.dmaster != ctdb->vnn && header.rsn == hdr->rsn)) {
|
||||
ret = ctdb_ltdb_store(ctdb_db, key, hdr, data);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to store record\n"));
|
||||
tdb_unlockall(ctdb_db->ltdb->tdb);
|
||||
return -1;
|
||||
DEBUG(0, (__location__ " Unable to store record\n"));
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
|
||||
}
|
||||
|
||||
tdb_unlockall(ctdb_db->ltdb->tdb);
|
||||
|
||||
ctdb_lock_all_databases_unmark(ctdb);
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
ctdb_lock_all_databases_unmark(ctdb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@ -301,7 +352,7 @@ static int traverse_setdmaster(struct tdb_context *tdb, TDB_DATA key, TDB_DATA d
|
||||
|
||||
ret = tdb_store(tdb, key, data, TDB_REPLACE);
|
||||
if (ret) {
|
||||
DEBUG(0,(__location__ "failed to write tdb data back ret:%d\n",ret));
|
||||
DEBUG(0,(__location__ " failed to write tdb data back ret:%d\n",ret));
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
@ -312,20 +363,25 @@ int32_t ctdb_control_set_dmaster(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
struct ctdb_control_set_dmaster *p = (struct ctdb_control_set_dmaster *)indata.dptr;
|
||||
struct ctdb_db_context *ctdb_db;
|
||||
|
||||
if (ctdb->freeze_mode != CTDB_FREEZE_FROZEN) {
|
||||
DEBUG(0,("rejecting ctdb_control_set_dmaster when not frozen\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctdb_db = find_ctdb_db(ctdb, p->db_id);
|
||||
if (!ctdb_db) {
|
||||
DEBUG(0,(__location__ " Unknown db 0x%08x\n", p->db_id));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tdb_lockall_nonblock(ctdb_db->ltdb->tdb) != 0) {
|
||||
DEBUG(0,(__location__ " Failed to get nonblock lock on entired db - failing\n"));
|
||||
if (ctdb_lock_all_databases_mark(ctdb) != 0) {
|
||||
DEBUG(0,(__location__ " Failed to get lock on entired db - failing\n"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
tdb_traverse(ctdb_db->ltdb->tdb, traverse_setdmaster, &p->dmaster);
|
||||
|
||||
tdb_unlockall(ctdb_db->ltdb->tdb);
|
||||
ctdb_lock_all_databases_unmark(ctdb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -335,10 +391,9 @@ static int traverse_cleardb(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
||||
ret = tdb_delete(tdb, key);
|
||||
if (ret) {
|
||||
DEBUG(0,(__location__ "failed to delete tdb record\n"));
|
||||
DEBUG(0,(__location__ " failed to delete tdb record\n"));
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
@ -350,24 +405,46 @@ int32_t ctdb_control_clear_db(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
uint32_t dbid = *(uint32_t *)indata.dptr;
|
||||
struct ctdb_db_context *ctdb_db;
|
||||
|
||||
if (ctdb->freeze_mode != CTDB_FREEZE_FROZEN) {
|
||||
DEBUG(0,("rejecting ctdb_control_clear_db when not frozen\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctdb_db = find_ctdb_db(ctdb, dbid);
|
||||
if (!ctdb_db) {
|
||||
DEBUG(0,(__location__ " Unknown db 0x%08x\n",dbid));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tdb_lockall_nonblock(ctdb_db->ltdb->tdb) != 0) {
|
||||
DEBUG(0,(__location__ " Failed to get nonblock lock on entired db - failing\n"));
|
||||
if (ctdb_lock_all_databases_mark(ctdb) != 0) {
|
||||
DEBUG(0,(__location__ " Failed to get lock on entired db - failing\n"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
tdb_traverse(ctdb_db->ltdb->tdb, traverse_cleardb, NULL);
|
||||
|
||||
tdb_unlockall(ctdb_db->ltdb->tdb);
|
||||
ctdb_lock_all_databases_unmark(ctdb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
set the recovery mode
|
||||
*/
|
||||
int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb, TDB_DATA indata,
|
||||
const char **errormsg)
|
||||
{
|
||||
uint32_t recmode = *(uint32_t *)indata.dptr;
|
||||
if (ctdb->freeze_mode != CTDB_FREEZE_FROZEN) {
|
||||
DEBUG(0,("Attempt to change recovery mode to %u when not frozen\n",
|
||||
recmode));
|
||||
(*errormsg) = "Cannot change recovery mode while not frozen";
|
||||
return -1;
|
||||
}
|
||||
ctdb->recovery_mode = recmode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int traverse_bumprsn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *p)
|
||||
{
|
||||
struct ctdb_ltdb_header *header = (struct ctdb_ltdb_header *)data.dptr;
|
||||
|
@ -57,11 +57,27 @@ static int set_recovery_mode(struct ctdb_context *ctdb, struct ctdb_node_map *no
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rec_mode == CTDB_RECOVERY_ACTIVE) {
|
||||
ret = ctdb_ctrl_freeze(ctdb, timeval_current_ofs(5, 0), nodemap->nodes[j].vnn);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ " Unable to freeze node %u\n", nodemap->nodes[j].vnn));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ctdb_ctrl_setrecmode(ctdb, timeval_current_ofs(1, 0), nodemap->nodes[j].vnn, rec_mode);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to set recmode on node %u\n", nodemap->nodes[j].vnn));
|
||||
DEBUG(0, (__location__ " Unable to set recmode on node %u\n", nodemap->nodes[j].vnn));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rec_mode == CTDB_RECOVERY_NORMAL) {
|
||||
ret = ctdb_ctrl_thaw(ctdb, timeval_current_ofs(5, 0), nodemap->nodes[j].vnn);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ " Unable to thaw node %u\n", nodemap->nodes[j].vnn));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -80,7 +96,7 @@ static int set_recovery_master(struct ctdb_context *ctdb, struct ctdb_node_map *
|
||||
|
||||
ret = ctdb_ctrl_setrecmaster(ctdb, timeval_current_ofs(1, 0), nodemap->nodes[j].vnn, vnn);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to set recmaster on node %u\n", nodemap->nodes[j].vnn));
|
||||
DEBUG(0, (__location__ " Unable to set recmaster on node %u\n", nodemap->nodes[j].vnn));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -106,7 +122,7 @@ static int create_missing_remote_databases(struct ctdb_context *ctdb, struct ctd
|
||||
|
||||
ret = ctdb_ctrl_getdbmap(ctdb, timeval_current_ofs(1, 0), nodemap->nodes[j].vnn, mem_ctx, &remote_dbmap);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to get dbids from node %u\n", vnn));
|
||||
DEBUG(0, (__location__ " Unable to get dbids from node %u\n", vnn));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -127,12 +143,12 @@ static int create_missing_remote_databases(struct ctdb_context *ctdb, struct ctd
|
||||
/* ok so we need to create this database */
|
||||
ctdb_ctrl_getdbname(ctdb, timeval_current_ofs(1, 0), vnn, dbmap->dbids[db], mem_ctx, &name);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to get dbname from node %u\n", vnn));
|
||||
DEBUG(0, (__location__ " Unable to get dbname from node %u\n", vnn));
|
||||
return -1;
|
||||
}
|
||||
ctdb_ctrl_createdb(ctdb, timeval_current_ofs(1, 0), nodemap->nodes[j].vnn, mem_ctx, name);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to create remote db:%s\n", name));
|
||||
DEBUG(0, (__location__ " Unable to create remote db:%s\n", name));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -160,7 +176,7 @@ static int create_missing_local_databases(struct ctdb_context *ctdb, struct ctdb
|
||||
|
||||
ret = ctdb_ctrl_getdbmap(ctdb, timeval_current_ofs(1, 0), nodemap->nodes[j].vnn, mem_ctx, &remote_dbmap);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to get dbids from node %u\n", vnn));
|
||||
DEBUG(0, (__location__ " Unable to get dbids from node %u\n", vnn));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -182,17 +198,17 @@ static int create_missing_local_databases(struct ctdb_context *ctdb, struct ctdb
|
||||
*/
|
||||
ctdb_ctrl_getdbname(ctdb, timeval_current_ofs(1, 0), nodemap->nodes[j].vnn, remote_dbmap->dbids[db], mem_ctx, &name);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to get dbname from node %u\n", nodemap->nodes[j].vnn));
|
||||
DEBUG(0, (__location__ " Unable to get dbname from node %u\n", nodemap->nodes[j].vnn));
|
||||
return -1;
|
||||
}
|
||||
ctdb_ctrl_createdb(ctdb, timeval_current_ofs(1, 0), vnn, mem_ctx, name);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to create local db:%s\n", name));
|
||||
DEBUG(0, (__location__ " Unable to create local db:%s\n", name));
|
||||
return -1;
|
||||
}
|
||||
ret = ctdb_ctrl_getdbmap(ctdb, timeval_current_ofs(1, 0), vnn, mem_ctx, dbmap);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to reread dbmap on node %u\n", vnn));
|
||||
DEBUG(0, (__location__ " Unable to reread dbmap on node %u\n", vnn));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -221,7 +237,7 @@ static int pull_all_remote_databases(struct ctdb_context *ctdb, struct ctdb_node
|
||||
}
|
||||
ret = ctdb_ctrl_copydb(ctdb, timeval_current_ofs(2, 0), nodemap->nodes[j].vnn, vnn, dbmap->dbids[i], CTDB_LMASTER_ANY, mem_ctx);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to copy db from node %u to node %u\n", nodemap->nodes[j].vnn, vnn));
|
||||
DEBUG(0, (__location__ " Unable to copy db from node %u to node %u\n", nodemap->nodes[j].vnn, vnn));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -245,7 +261,7 @@ static int update_dmaster_on_all_databases(struct ctdb_context *ctdb, struct ctd
|
||||
}
|
||||
ret = ctdb_ctrl_setdmaster(ctdb, timeval_current_ofs(1, 0), nodemap->nodes[j].vnn, ctdb, dbmap->dbids[i], vnn);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to set dmaster for node %u db:0x%08x\n", nodemap->nodes[j].vnn, dbmap->dbids[i]));
|
||||
DEBUG(0, (__location__ " Unable to set dmaster for node %u db:0x%08x\n", nodemap->nodes[j].vnn, dbmap->dbids[i]));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -289,7 +305,7 @@ static int push_all_local_databases(struct ctdb_context *ctdb, struct ctdb_node_
|
||||
}
|
||||
ret = ctdb_ctrl_copydb(ctdb, timeval_current_ofs(1, 0), vnn, nodemap->nodes[j].vnn, dbmap->dbids[i], CTDB_LMASTER_ANY, mem_ctx);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to copy db from node %u to node %u\n", vnn, nodemap->nodes[j].vnn));
|
||||
DEBUG(0, (__location__ " Unable to copy db from node %u to node %u\n", vnn, nodemap->nodes[j].vnn));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -312,7 +328,7 @@ static int update_vnnmap_on_all_nodes(struct ctdb_context *ctdb, struct ctdb_nod
|
||||
|
||||
ret = ctdb_ctrl_setvnnmap(ctdb, timeval_current_ofs(1, 0), nodemap->nodes[j].vnn, mem_ctx, vnnmap);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to set vnnmap for node %u\n", vnn));
|
||||
DEBUG(0, (__location__ " Unable to set vnnmap for node %u\n", vnn));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -329,7 +345,14 @@ static int do_recovery(struct ctdb_context *ctdb, struct event_context *ev,
|
||||
uint32_t generation;
|
||||
struct ctdb_dbid_map *dbmap;
|
||||
|
||||
DEBUG(0, (__location__ "Recovery initiated\n"));
|
||||
DEBUG(0, (__location__ " Recovery initiated\n"));
|
||||
|
||||
/* set recovery mode to active on all nodes */
|
||||
ret = set_recovery_mode(ctdb, nodemap, CTDB_RECOVERY_ACTIVE);
|
||||
if (ret!=0) {
|
||||
DEBUG(0, (__location__ " Unable to set recovery mode to active on cluster\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* pick a new generation number */
|
||||
generation = random();
|
||||
@ -347,23 +370,14 @@ static int do_recovery(struct ctdb_context *ctdb, struct event_context *ev,
|
||||
vnnmap->generation = generation;
|
||||
ret = ctdb_ctrl_setvnnmap(ctdb, timeval_current_ofs(1, 0), vnn, mem_ctx, vnnmap);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to set vnnmap for node %u\n", vnn));
|
||||
DEBUG(0, (__location__ " Unable to set vnnmap for node %u\n", vnn));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* set recovery mode to active on all nodes */
|
||||
ret = set_recovery_mode(ctdb, nodemap, CTDB_RECOVERY_ACTIVE);
|
||||
if (ret!=0) {
|
||||
DEBUG(0, (__location__ "Unable to set recovery mode to active on cluster\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* get a list of all databases */
|
||||
ret = ctdb_ctrl_getdbmap(ctdb, timeval_current_ofs(1, 0), vnn, mem_ctx, &dbmap);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to get dbids from node :%d\n", vnn));
|
||||
DEBUG(0, (__location__ " Unable to get dbids from node :%d\n", vnn));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -372,7 +386,7 @@ static int do_recovery(struct ctdb_context *ctdb, struct event_context *ev,
|
||||
/* verify that all other nodes have all our databases */
|
||||
ret = create_missing_remote_databases(ctdb, nodemap, vnn, dbmap, mem_ctx);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to create missing remote databases\n"));
|
||||
DEBUG(0, (__location__ " Unable to create missing remote databases\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -381,7 +395,7 @@ static int do_recovery(struct ctdb_context *ctdb, struct event_context *ev,
|
||||
/* verify that we have all the databases any other node has */
|
||||
ret = create_missing_local_databases(ctdb, nodemap, vnn, &dbmap, mem_ctx);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to create missing local databases\n"));
|
||||
DEBUG(0, (__location__ " Unable to create missing local databases\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -390,27 +404,15 @@ static int do_recovery(struct ctdb_context *ctdb, struct event_context *ev,
|
||||
/* verify that all other nodes have all our databases */
|
||||
ret = create_missing_remote_databases(ctdb, nodemap, vnn, dbmap, mem_ctx);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to create missing remote databases\n"));
|
||||
DEBUG(0, (__location__ " Unable to create missing remote databases\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* repoint all local and remote database records to an invalid
|
||||
node as being dmaster to stop the shortcut from working
|
||||
*/
|
||||
ret = update_dmaster_on_all_databases(ctdb, nodemap, 0xffffffff, dbmap, mem_ctx);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to update dmaster on all databases\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* pull all remote databases onto the local node */
|
||||
ret = pull_all_remote_databases(ctdb, nodemap, vnn, dbmap, mem_ctx);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to pull remote databases\n"));
|
||||
DEBUG(0, (__location__ " Unable to pull remote databases\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -419,7 +421,7 @@ static int do_recovery(struct ctdb_context *ctdb, struct event_context *ev,
|
||||
/* push all local databases to the remote nodes */
|
||||
ret = push_all_local_databases(ctdb, nodemap, vnn, dbmap, mem_ctx);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to push local databases\n"));
|
||||
DEBUG(0, (__location__ " Unable to push local databases\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -443,7 +445,7 @@ static int do_recovery(struct ctdb_context *ctdb, struct event_context *ev,
|
||||
/* update to the new vnnmap on all nodes */
|
||||
ret = update_vnnmap_on_all_nodes(ctdb, nodemap, vnn, vnnmap, mem_ctx);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to update vnnmap on all nodes\n"));
|
||||
DEBUG(0, (__location__ " Unable to update vnnmap on all nodes\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -451,7 +453,7 @@ static int do_recovery(struct ctdb_context *ctdb, struct event_context *ev,
|
||||
/* update recmaster to point to us for all nodes */
|
||||
ret = set_recovery_master(ctdb, nodemap, vnn);
|
||||
if (ret!=0) {
|
||||
DEBUG(0, (__location__ "Unable to set recovery master\n"));
|
||||
DEBUG(0, (__location__ " Unable to set recovery master\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -461,7 +463,7 @@ static int do_recovery(struct ctdb_context *ctdb, struct event_context *ev,
|
||||
*/
|
||||
ret = update_dmaster_on_all_databases(ctdb, nodemap, vnn, dbmap, mem_ctx);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to update dmaster on all databases\n"));
|
||||
DEBUG(0, (__location__ " Unable to update dmaster on all databases\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -478,12 +480,12 @@ static int do_recovery(struct ctdb_context *ctdb, struct event_context *ev,
|
||||
/* disable recovery mode */
|
||||
ret = set_recovery_mode(ctdb, nodemap, CTDB_RECOVERY_NORMAL);
|
||||
if (ret!=0) {
|
||||
DEBUG(0, (__location__ "Unable to set recovery mode to normal on cluster\n"));
|
||||
DEBUG(0, (__location__ " Unable to set recovery mode to normal on cluster\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
DEBUG(0, (__location__ "Recovery complete\n"));
|
||||
DEBUG(0, (__location__ " Recovery complete\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -513,7 +515,7 @@ static int send_election_request(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
|
||||
*/
|
||||
ret = ctdb_ctrl_setrecmaster(ctdb, timeval_current_ofs(1, 0), vnn, vnn);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "failed to send recmaster election request"));
|
||||
DEBUG(0, (__location__ " failed to send recmaster election request"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -551,7 +553,7 @@ static void election_handler(struct ctdb_context *ctdb, uint64_t srvid,
|
||||
if (em->vnn > ctdb_get_vnn(ctdb)) {
|
||||
ret = send_election_request(ctdb, mem_ctx, ctdb_get_vnn(ctdb));
|
||||
if (ret!=0) {
|
||||
DEBUG(0, (__location__ "failed to initiate recmaster election"));
|
||||
DEBUG(0, (__location__ " failed to initiate recmaster election"));
|
||||
}
|
||||
talloc_free(mem_ctx);
|
||||
return;
|
||||
@ -560,7 +562,7 @@ static void election_handler(struct ctdb_context *ctdb, uint64_t srvid,
|
||||
/* ok, let that guy become recmaster then */
|
||||
ret = ctdb_ctrl_setrecmaster(ctdb, timeval_current_ofs(1, 0), ctdb_get_vnn(ctdb), em->vnn);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "failed to send recmaster election request"));
|
||||
DEBUG(0, (__location__ " failed to send recmaster election request"));
|
||||
talloc_free(mem_ctx);
|
||||
return;
|
||||
}
|
||||
@ -577,13 +579,13 @@ static void force_election(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, uint3
|
||||
/* set all nodes to recovery mode to stop all internode traffic */
|
||||
ret = set_recovery_mode(ctdb, nodemap, CTDB_RECOVERY_ACTIVE);
|
||||
if (ret!=0) {
|
||||
DEBUG(0, (__location__ "Unable to set recovery mode to active on cluster\n"));
|
||||
DEBUG(0, (__location__ " Unable to set recovery mode to active on cluster\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = send_election_request(ctdb, mem_ctx, vnn);
|
||||
if (ret!=0) {
|
||||
DEBUG(0, (__location__ "failed to initiate recmaster election"));
|
||||
DEBUG(0, (__location__ " failed to initiate recmaster election"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -632,7 +634,7 @@ again:
|
||||
/* get the vnnmap */
|
||||
ret = ctdb_ctrl_getvnnmap(ctdb, timeval_current_ofs(1, 0), vnn, mem_ctx, &vnnmap);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to get vnnmap from node %u\n", vnn));
|
||||
DEBUG(0, (__location__ " Unable to get vnnmap from node %u\n", vnn));
|
||||
goto again;
|
||||
}
|
||||
|
||||
@ -640,7 +642,7 @@ again:
|
||||
/* get number of nodes */
|
||||
ret = ctdb_ctrl_getnodemap(ctdb, timeval_current_ofs(1, 0), vnn, mem_ctx, &nodemap);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to get nodemap from node %u\n", vnn));
|
||||
DEBUG(0, (__location__ " Unable to get nodemap from node %u\n", vnn));
|
||||
goto again;
|
||||
}
|
||||
|
||||
@ -657,7 +659,7 @@ again:
|
||||
/* check which node is the recovery master */
|
||||
ret = ctdb_ctrl_getrecmaster(ctdb, timeval_current_ofs(1, 0), vnn, &recmaster);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to get recmaster from node %u\n", vnn));
|
||||
DEBUG(0, (__location__ " Unable to get recmaster from node %u\n", vnn));
|
||||
goto again;
|
||||
}
|
||||
|
||||
@ -693,7 +695,7 @@ again:
|
||||
|
||||
ret = ctdb_ctrl_getrecmaster(ctdb, timeval_current_ofs(1, 0), nodemap->nodes[j].vnn, &recmaster);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to get recmaster from node %u\n", vnn));
|
||||
DEBUG(0, (__location__ " Unable to get recmaster from node %u\n", vnn));
|
||||
goto again;
|
||||
}
|
||||
|
||||
@ -719,7 +721,7 @@ again:
|
||||
goto again;
|
||||
}
|
||||
if (recmode!=CTDB_RECOVERY_NORMAL) {
|
||||
DEBUG(0, (__location__ "Node:%d was in recovery mode. Restart recovery process\n", nodemap->nodes[j].vnn));
|
||||
DEBUG(0, (__location__ " Node:%d was in recovery mode. Restart recovery process\n", nodemap->nodes[j].vnn));
|
||||
do_recovery(ctdb, ev, mem_ctx, vnn, num_active, nodemap, vnnmap);
|
||||
goto again;
|
||||
}
|
||||
@ -739,7 +741,7 @@ again:
|
||||
|
||||
ret = ctdb_ctrl_getnodemap(ctdb, timeval_current_ofs(1, 0), nodemap->nodes[j].vnn, mem_ctx, &remote_nodemap);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to get nodemap from remote node %u\n", nodemap->nodes[j].vnn));
|
||||
DEBUG(0, (__location__ " Unable to get nodemap from remote node %u\n", nodemap->nodes[j].vnn));
|
||||
goto again;
|
||||
}
|
||||
|
||||
@ -747,7 +749,7 @@ again:
|
||||
then this is a good reason to try recovery
|
||||
*/
|
||||
if (remote_nodemap->num != nodemap->num) {
|
||||
DEBUG(0, (__location__ "Remote node:%d has different node count. %d vs %d of the local node\n", nodemap->nodes[j].vnn, remote_nodemap->num, nodemap->num));
|
||||
DEBUG(0, (__location__ " Remote node:%d has different node count. %d vs %d of the local node\n", nodemap->nodes[j].vnn, remote_nodemap->num, nodemap->num));
|
||||
do_recovery(ctdb, ev, mem_ctx, vnn, num_active, nodemap, vnnmap);
|
||||
goto again;
|
||||
}
|
||||
@ -758,7 +760,7 @@ again:
|
||||
for (i=0;i<nodemap->num;i++) {
|
||||
if ((remote_nodemap->nodes[i].vnn != nodemap->nodes[i].vnn)
|
||||
|| (remote_nodemap->nodes[i].flags != nodemap->nodes[i].flags)) {
|
||||
DEBUG(0, (__location__ "Remote node:%d has different nodemap.\n", nodemap->nodes[j].vnn));
|
||||
DEBUG(0, (__location__ " Remote node:%d has different nodemap.\n", nodemap->nodes[j].vnn));
|
||||
do_recovery(ctdb, ev, mem_ctx, vnn, num_active, nodemap, vnnmap);
|
||||
goto again;
|
||||
}
|
||||
@ -771,7 +773,7 @@ again:
|
||||
as there are active nodes or we will have to do a recovery
|
||||
*/
|
||||
if (vnnmap->size != num_active) {
|
||||
DEBUG(0, (__location__ "The vnnmap count is different from the number of active nodes. %d vs %d\n", vnnmap->size, num_active));
|
||||
DEBUG(0, (__location__ " The vnnmap count is different from the number of active nodes. %d vs %d\n", vnnmap->size, num_active));
|
||||
do_recovery(ctdb, ev, mem_ctx, vnn, num_active, nodemap, vnnmap);
|
||||
goto again;
|
||||
}
|
||||
@ -793,7 +795,7 @@ again:
|
||||
}
|
||||
}
|
||||
if (i==vnnmap->size) {
|
||||
DEBUG(0, (__location__ "Node %d is active in the nodemap but did not exist in the vnnmap\n", nodemap->nodes[j].vnn));
|
||||
DEBUG(0, (__location__ " Node %d is active in the nodemap but did not exist in the vnnmap\n", nodemap->nodes[j].vnn));
|
||||
do_recovery(ctdb, ev, mem_ctx, vnn, num_active, nodemap, vnnmap);
|
||||
goto again;
|
||||
}
|
||||
@ -813,20 +815,20 @@ again:
|
||||
|
||||
ret = ctdb_ctrl_getvnnmap(ctdb, timeval_current_ofs(1, 0), nodemap->nodes[j].vnn, mem_ctx, &remote_vnnmap);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__ "Unable to get vnnmap from remote node %u\n", nodemap->nodes[j].vnn));
|
||||
DEBUG(0, (__location__ " Unable to get vnnmap from remote node %u\n", nodemap->nodes[j].vnn));
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* verify the vnnmap generation is the same */
|
||||
if (vnnmap->generation != remote_vnnmap->generation) {
|
||||
DEBUG(0, (__location__ "Remote node %d has different generation of vnnmap. %d vs %d (ours)\n", nodemap->nodes[j].vnn, remote_vnnmap->generation, vnnmap->generation));
|
||||
DEBUG(0, (__location__ " Remote node %d has different generation of vnnmap. %d vs %d (ours)\n", nodemap->nodes[j].vnn, remote_vnnmap->generation, vnnmap->generation));
|
||||
do_recovery(ctdb, ev, mem_ctx, vnn, num_active, nodemap, vnnmap);
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* verify the vnnmap size is the same */
|
||||
if (vnnmap->size != remote_vnnmap->size) {
|
||||
DEBUG(0, (__location__ "Remote node %d has different size of vnnmap. %d vs %d (ours)\n", nodemap->nodes[j].vnn, remote_vnnmap->size, vnnmap->size));
|
||||
DEBUG(0, (__location__ " Remote node %d has different size of vnnmap. %d vs %d (ours)\n", nodemap->nodes[j].vnn, remote_vnnmap->size, vnnmap->size));
|
||||
do_recovery(ctdb, ev, mem_ctx, vnn, num_active, nodemap, vnnmap);
|
||||
goto again;
|
||||
}
|
||||
@ -834,7 +836,7 @@ again:
|
||||
/* verify the vnnmap is the same */
|
||||
for (i=0;i<vnnmap->size;i++) {
|
||||
if (remote_vnnmap->map[i] != vnnmap->map[i]) {
|
||||
DEBUG(0, (__location__ "Remote node %d has different vnnmap.\n", nodemap->nodes[j].vnn));
|
||||
DEBUG(0, (__location__ " Remote node %d has different vnnmap.\n", nodemap->nodes[j].vnn));
|
||||
do_recovery(ctdb, ev, mem_ctx, vnn, num_active, nodemap, vnnmap);
|
||||
goto again;
|
||||
}
|
||||
@ -895,7 +897,7 @@ int main(int argc, const char *argv[])
|
||||
/* initialise ctdb */
|
||||
ctdb = ctdb_cmdline_client(ev);
|
||||
if (ctdb == NULL) {
|
||||
DEBUG(0, (__location__ "Failed to init ctdb\n"));
|
||||
DEBUG(0, (__location__ " Failed to init ctdb\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -290,6 +290,7 @@ int ctdb_ctrl_write_record(struct ctdb_context *ctdb, uint32_t destnode, TALLOC_
|
||||
|
||||
#define CTDB_RECOVERY_NORMAL 0
|
||||
#define CTDB_RECOVERY_ACTIVE 1
|
||||
|
||||
/*
|
||||
get the recovery mode of a remote node
|
||||
*/
|
||||
@ -327,4 +328,7 @@ int ctdb_dump_db(struct ctdb_db_context *ctdb_db, FILE *f);
|
||||
*/
|
||||
int ctdb_ctrl_getpid(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *pid);
|
||||
|
||||
int ctdb_ctrl_freeze(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
|
||||
int ctdb_ctrl_thaw(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
|
||||
|
||||
#endif
|
||||
|
@ -75,6 +75,7 @@ typedef void (*ctdb_queue_cb_fn_t)(uint8_t *data, size_t length,
|
||||
/* used for callbacks in ctdb_control requests */
|
||||
typedef void (*ctdb_control_callback_fn_t)(struct ctdb_context *,
|
||||
uint32_t status, TDB_DATA data,
|
||||
const char *errormsg,
|
||||
void *private_data);
|
||||
|
||||
/*
|
||||
@ -136,6 +137,8 @@ struct ctdb_daemon_data {
|
||||
*/
|
||||
struct ctdb_status {
|
||||
uint32_t num_clients;
|
||||
uint32_t frozen;
|
||||
uint32_t recovering;
|
||||
uint32_t client_packets_sent;
|
||||
uint32_t client_packets_recv;
|
||||
uint32_t node_packets_sent;
|
||||
@ -217,11 +220,15 @@ struct ctdb_write_record {
|
||||
uint32_t datalen;
|
||||
unsigned char blob[1];
|
||||
};
|
||||
|
||||
|
||||
enum ctdb_freeze_mode {CTDB_FREEZE_NONE, CTDB_FREEZE_PENDING, CTDB_FREEZE_FROZEN};
|
||||
|
||||
/* main state of the ctdb daemon */
|
||||
struct ctdb_context {
|
||||
struct event_context *ev;
|
||||
uint32_t recovery_mode;
|
||||
enum ctdb_freeze_mode freeze_mode;
|
||||
struct ctdb_freeze_handle *freeze_handle;
|
||||
struct ctdb_address address;
|
||||
const char *name;
|
||||
const char *db_directory;
|
||||
@ -344,6 +351,8 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS,
|
||||
CTDB_CONTROL_GET_RECMASTER,
|
||||
CTDB_CONTROL_SET_RECMASTER,
|
||||
CTDB_CONTROL_BUMP_RSN,
|
||||
CTDB_CONTROL_FREEZE,
|
||||
CTDB_CONTROL_THAW,
|
||||
};
|
||||
|
||||
|
||||
@ -519,6 +528,7 @@ struct ctdb_reply_control {
|
||||
struct ctdb_req_header hdr;
|
||||
int32_t status;
|
||||
uint32_t datalen;
|
||||
uint32_t errorlen;
|
||||
uint8_t data[1];
|
||||
};
|
||||
|
||||
@ -549,12 +559,12 @@ void ctdb_queue_packet(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
|
||||
int ctdb_ltdb_lock_requeue(struct ctdb_db_context *ctdb_db,
|
||||
TDB_DATA key, struct ctdb_req_header *hdr,
|
||||
void (*recv_pkt)(void *, uint8_t *, uint32_t ),
|
||||
void *recv_context);
|
||||
void *recv_context, bool ignore_generation);
|
||||
int ctdb_ltdb_lock_fetch_requeue(struct ctdb_db_context *ctdb_db,
|
||||
TDB_DATA key, struct ctdb_ltdb_header *header,
|
||||
struct ctdb_req_header *hdr, TDB_DATA *data,
|
||||
void (*recv_pkt)(void *, uint8_t *, uint32_t ),
|
||||
void *recv_context);
|
||||
void *recv_context, bool ignore_generation);
|
||||
void ctdb_recv_pkt(struct ctdb_context *ctdb, uint8_t *data, uint32_t length);
|
||||
|
||||
struct ctdb_call_state *ctdb_call_local_send(struct ctdb_db_context *ctdb_db,
|
||||
@ -703,7 +713,7 @@ int ctdb_daemon_set_call(struct ctdb_context *ctdb, uint32_t db_id,
|
||||
int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid,
|
||||
uint32_t opcode, uint32_t flags, TDB_DATA data,
|
||||
TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status,
|
||||
struct timeval *timeout);
|
||||
struct timeval *timeout, char **errormsg);
|
||||
|
||||
|
||||
|
||||
@ -783,4 +793,11 @@ int32_t ctdb_control_set_dmaster(struct ctdb_context *ctdb, TDB_DATA indata);
|
||||
int32_t ctdb_control_clear_db(struct ctdb_context *ctdb, TDB_DATA indata);
|
||||
int32_t ctdb_control_bump_rsn(struct ctdb_context *ctdb, TDB_DATA indata);
|
||||
|
||||
int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb, TDB_DATA data, const char **);
|
||||
void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_control *c,
|
||||
TDB_DATA *outdata, int32_t status, const char *errormsg);
|
||||
|
||||
int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply);
|
||||
int32_t ctdb_control_thaw(struct ctdb_context *ctdb);
|
||||
|
||||
#endif
|
||||
|
@ -290,6 +290,10 @@ int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
|
||||
/* lock/unlock entire database */
|
||||
static int _tdb_lockall(struct tdb_context *tdb, int ltype, int op)
|
||||
{
|
||||
bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK);
|
||||
|
||||
ltype &= ~TDB_MARK_LOCK;
|
||||
|
||||
/* There are no locks on read-only dbs */
|
||||
if (tdb->read_only || tdb->traverse_read)
|
||||
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
|
||||
@ -309,7 +313,8 @@ static int _tdb_lockall(struct tdb_context *tdb, int ltype, int op)
|
||||
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
|
||||
}
|
||||
|
||||
if (tdb->methods->tdb_brlock(tdb, FREELIST_TOP, ltype, op,
|
||||
if (!mark_lock &&
|
||||
tdb->methods->tdb_brlock(tdb, FREELIST_TOP, ltype, op,
|
||||
0, 4*tdb->header.hash_size)) {
|
||||
if (op == F_SETLKW) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lockall failed (%s)\n", strerror(errno)));
|
||||
@ -328,6 +333,10 @@ static int _tdb_lockall(struct tdb_context *tdb, int ltype, int op)
|
||||
/* unlock entire db */
|
||||
static int _tdb_unlockall(struct tdb_context *tdb, int ltype)
|
||||
{
|
||||
bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK);
|
||||
|
||||
ltype &= ~TDB_MARK_LOCK;
|
||||
|
||||
/* There are no locks on read-only dbs */
|
||||
if (tdb->read_only || tdb->traverse_read) {
|
||||
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
|
||||
@ -342,7 +351,8 @@ static int _tdb_unlockall(struct tdb_context *tdb, int ltype)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tdb->methods->tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW,
|
||||
if (!mark_lock &&
|
||||
tdb->methods->tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW,
|
||||
0, 4*tdb->header.hash_size)) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno)));
|
||||
return -1;
|
||||
@ -360,6 +370,18 @@ int tdb_lockall(struct tdb_context *tdb)
|
||||
return _tdb_lockall(tdb, F_WRLCK, F_SETLKW);
|
||||
}
|
||||
|
||||
/* lock entire database with write lock - mark only */
|
||||
int tdb_lockall_mark(struct tdb_context *tdb)
|
||||
{
|
||||
return _tdb_lockall(tdb, F_WRLCK | TDB_MARK_LOCK, F_SETLKW);
|
||||
}
|
||||
|
||||
/* unlock entire database with write lock - unmark only */
|
||||
int tdb_lockall_unmark(struct tdb_context *tdb)
|
||||
{
|
||||
return _tdb_unlockall(tdb, F_WRLCK | TDB_MARK_LOCK);
|
||||
}
|
||||
|
||||
/* lock entire database with write lock - nonblocking varient */
|
||||
int tdb_lockall_nonblock(struct tdb_context *tdb)
|
||||
{
|
||||
|
@ -121,6 +121,8 @@ int tdb_unlockall(struct tdb_context *tdb);
|
||||
int tdb_lockall_read(struct tdb_context *tdb);
|
||||
int tdb_lockall_read_nonblock(struct tdb_context *tdb);
|
||||
int tdb_unlockall_read(struct tdb_context *tdb);
|
||||
int tdb_lockall_mark(struct tdb_context *tdb);
|
||||
int tdb_lockall_unmark(struct tdb_context *tdb);
|
||||
const char *tdb_name(struct tdb_context *tdb);
|
||||
int tdb_fd(struct tdb_context *tdb);
|
||||
tdb_log_func tdb_log_fn(struct tdb_context *tdb);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "../include/ctdb.h"
|
||||
#include "../include/ctdb_private.h"
|
||||
|
||||
static int timelimit = 3;
|
||||
|
||||
/*
|
||||
show usage message
|
||||
@ -56,6 +57,8 @@ static void usage(void)
|
||||
" setrecmaster <vnn> <master_vnn> set recovery master\n"
|
||||
" attach <dbname> attach a database\n"
|
||||
" getpid <vnn> get the pid of a ctdb daemon\n"
|
||||
" freeze <vnn|all> freeze a node\n"
|
||||
" thaw <vnn|all> thaw a node\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
@ -93,13 +96,15 @@ static void show_status(struct ctdb_status *s)
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
|
||||
int i;
|
||||
const char *prefix=NULL;
|
||||
size_t preflen=0;
|
||||
int preflen=0;
|
||||
const struct {
|
||||
const char *name;
|
||||
uint32_t offset;
|
||||
} fields[] = {
|
||||
#define STATUS_FIELD(n) { #n, offsetof(struct ctdb_status, n) }
|
||||
STATUS_FIELD(num_clients),
|
||||
STATUS_FIELD(frozen),
|
||||
STATUS_FIELD(recovering),
|
||||
STATUS_FIELD(client_packets_sent),
|
||||
STATUS_FIELD(client_packets_recv),
|
||||
STATUS_FIELD(node_packets_sent),
|
||||
@ -175,7 +180,7 @@ static int control_status_all(struct ctdb_context *ctdb)
|
||||
uint32_t *nodes;
|
||||
uint32_t num_nodes;
|
||||
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(1, 0), ctdb, &num_nodes);
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(timelimit, 0), ctdb, &num_nodes);
|
||||
CTDB_NO_MEMORY(ctdb, nodes);
|
||||
|
||||
ZERO_STRUCT(status);
|
||||
@ -245,7 +250,7 @@ static int control_status_reset_all(struct ctdb_context *ctdb)
|
||||
uint32_t *nodes;
|
||||
uint32_t num_nodes;
|
||||
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(1, 0), ctdb, &num_nodes);
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(timelimit, 0), ctdb, &num_nodes);
|
||||
CTDB_NO_MEMORY(ctdb, nodes);
|
||||
|
||||
for (i=0;i<num_nodes;i++) {
|
||||
@ -300,7 +305,7 @@ static int control_getvnnmap(struct ctdb_context *ctdb, int argc, const char **a
|
||||
|
||||
vnn = strtoul(argv[0], NULL, 0);
|
||||
|
||||
ret = ctdb_ctrl_getvnnmap(ctdb, timeval_current_ofs(1, 0), vnn, ctdb, &vnnmap);
|
||||
ret = ctdb_ctrl_getvnnmap(ctdb, timeval_current_ofs(timelimit, 0), vnn, ctdb, &vnnmap);
|
||||
if (ret != 0) {
|
||||
printf("Unable to get vnnmap from node %u\n", vnn);
|
||||
return ret;
|
||||
@ -328,7 +333,7 @@ static int control_getpid(struct ctdb_context *ctdb, int argc, const char **argv
|
||||
|
||||
vnn = strtoul(argv[0], NULL, 0);
|
||||
|
||||
ret = ctdb_ctrl_getpid(ctdb, timeval_current_ofs(1, 0), vnn, &pid);
|
||||
ret = ctdb_ctrl_getpid(ctdb, timeval_current_ofs(timelimit, 0), vnn, &pid);
|
||||
if (ret != 0) {
|
||||
printf("Unable to get daemon pid from node %u\n", vnn);
|
||||
return ret;
|
||||
@ -353,7 +358,7 @@ static int control_getrecmode(struct ctdb_context *ctdb, int argc, const char **
|
||||
|
||||
vnn = strtoul(argv[0], NULL, 0);
|
||||
|
||||
ret = ctdb_ctrl_getrecmode(ctdb, timeval_current_ofs(1, 0), vnn, &recmode);
|
||||
ret = ctdb_ctrl_getrecmode(ctdb, timeval_current_ofs(timelimit, 0), vnn, &recmode);
|
||||
if (ret != 0) {
|
||||
printf("Unable to get recmode from node %u\n", vnn);
|
||||
return ret;
|
||||
@ -379,7 +384,7 @@ static int control_setrecmode(struct ctdb_context *ctdb, int argc, const char **
|
||||
vnn = strtoul(argv[0], NULL, 0);
|
||||
recmode = strtoul(argv[1], NULL, 0);
|
||||
|
||||
ret = ctdb_ctrl_setrecmode(ctdb, timeval_current_ofs(1, 0), vnn, recmode);
|
||||
ret = ctdb_ctrl_setrecmode(ctdb, timeval_current_ofs(timelimit, 0), vnn, recmode);
|
||||
if (ret != 0) {
|
||||
printf("Unable to set recmode on node %u\n", vnn);
|
||||
return ret;
|
||||
@ -403,7 +408,7 @@ static int control_getrecmaster(struct ctdb_context *ctdb, int argc, const char
|
||||
|
||||
vnn = strtoul(argv[0], NULL, 0);
|
||||
|
||||
ret = ctdb_ctrl_getrecmaster(ctdb, timeval_current_ofs(1, 0), vnn, &recmaster);
|
||||
ret = ctdb_ctrl_getrecmaster(ctdb, timeval_current_ofs(timelimit, 0), vnn, &recmaster);
|
||||
if (ret != 0) {
|
||||
printf("Unable to get recmaster from node %u\n", vnn);
|
||||
return ret;
|
||||
@ -429,7 +434,7 @@ static int control_setrecmaster(struct ctdb_context *ctdb, int argc, const char
|
||||
vnn = strtoul(argv[0], NULL, 0);
|
||||
recmaster = strtoul(argv[1], NULL, 0);
|
||||
|
||||
ret = ctdb_ctrl_setrecmaster(ctdb, timeval_current_ofs(1, 0), vnn, recmaster);
|
||||
ret = ctdb_ctrl_setrecmaster(ctdb, timeval_current_ofs(timelimit, 0), vnn, recmaster);
|
||||
if (ret != 0) {
|
||||
printf("Unable to set recmaster on node %u\n", vnn);
|
||||
return ret;
|
||||
@ -483,7 +488,9 @@ static int control_catdb(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
keystr = hex_encode(ctdb, keys.keys[i].dptr, keys.keys[i].dsize);
|
||||
datastr = hex_encode(ctdb, keys.data[i].dptr, keys.data[i].dsize);
|
||||
|
||||
printf("rsn:%llu lmaster:%d dmaster:%d key:%s data:%s\n", keys.headers[i].rsn, keys.lmasters[i], keys.headers[i].dmaster, keystr, datastr);
|
||||
printf("rsn:%llu lmaster:%d dmaster:%d key:%s data:%s\n",
|
||||
(unsigned long long)keys.headers[i].rsn, keys.lmasters[i],
|
||||
keys.headers[i].dmaster, keystr, datastr);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
@ -512,7 +519,7 @@ static int control_cpdb(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
dbid = strtoul(argv[2], NULL, 0);
|
||||
|
||||
mem_ctx = talloc_new(ctdb);
|
||||
ret = ctdb_ctrl_copydb(ctdb, timeval_current_ofs(1, 0), fromvnn, tovnn, dbid, CTDB_LMASTER_ANY, mem_ctx);
|
||||
ret = ctdb_ctrl_copydb(ctdb, timeval_current_ofs(timelimit, 0), fromvnn, tovnn, dbid, CTDB_LMASTER_ANY, mem_ctx);
|
||||
if (ret != 0) {
|
||||
printf("Unable to copy db from node %u to node %u\n", fromvnn, tovnn);
|
||||
return ret;
|
||||
@ -537,7 +544,7 @@ static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **ar
|
||||
|
||||
vnn = strtoul(argv[0], NULL, 0);
|
||||
|
||||
ret = ctdb_ctrl_getdbmap(ctdb, timeval_current_ofs(1, 0), vnn, ctdb, &dbmap);
|
||||
ret = ctdb_ctrl_getdbmap(ctdb, timeval_current_ofs(timelimit, 0), vnn, ctdb, &dbmap);
|
||||
if (ret != 0) {
|
||||
printf("Unable to get dbids from node %u\n", vnn);
|
||||
return ret;
|
||||
@ -548,8 +555,8 @@ static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **ar
|
||||
const char *path;
|
||||
const char *name;
|
||||
|
||||
ctdb_ctrl_getdbpath(ctdb, timeval_current_ofs(1, 0), CTDB_CURRENT_NODE, dbmap->dbids[i], ctdb, &path);
|
||||
ctdb_ctrl_getdbname(ctdb, timeval_current_ofs(1, 0), CTDB_CURRENT_NODE, dbmap->dbids[i], ctdb, &name);
|
||||
ctdb_ctrl_getdbpath(ctdb, timeval_current_ofs(timelimit, 0), CTDB_CURRENT_NODE, dbmap->dbids[i], ctdb, &path);
|
||||
ctdb_ctrl_getdbname(ctdb, timeval_current_ofs(timelimit, 0), CTDB_CURRENT_NODE, dbmap->dbids[i], ctdb, &name);
|
||||
printf("dbid:0x%08x name:%s path:%s\n", dbmap->dbids[i], name, path);
|
||||
}
|
||||
|
||||
@ -571,7 +578,7 @@ static int control_getnodemap(struct ctdb_context *ctdb, int argc, const char **
|
||||
|
||||
vnn = strtoul(argv[0], NULL, 0);
|
||||
|
||||
ret = ctdb_ctrl_getnodemap(ctdb, timeval_current_ofs(1, 0), vnn, ctdb, &nodemap);
|
||||
ret = ctdb_ctrl_getnodemap(ctdb, timeval_current_ofs(timelimit, 0), vnn, ctdb, &nodemap);
|
||||
if (ret != 0) {
|
||||
printf("Unable to get nodemap from node %u\n", vnn);
|
||||
return ret;
|
||||
@ -616,7 +623,7 @@ static int control_setvnnmap(struct ctdb_context *ctdb, int argc, const char **a
|
||||
vnnmap->map[i] = strtoul(argv[3+i], NULL, 0);
|
||||
}
|
||||
|
||||
ret = ctdb_ctrl_setvnnmap(ctdb, timeval_current_ofs(1, 0), vnn, ctdb, vnnmap);
|
||||
ret = ctdb_ctrl_setvnnmap(ctdb, timeval_current_ofs(timelimit, 0), vnn, ctdb, vnnmap);
|
||||
if (ret != 0) {
|
||||
printf("Unable to set vnnmap for node %u\n", vnn);
|
||||
return ret;
|
||||
@ -641,7 +648,7 @@ static int control_setdmaster(struct ctdb_context *ctdb, int argc, const char **
|
||||
dbid = strtoul(argv[1], NULL, 0);
|
||||
dmaster = strtoul(argv[2], NULL, 0);
|
||||
|
||||
ret = ctdb_ctrl_setdmaster(ctdb, timeval_current_ofs(1, 0), vnn, ctdb, dbid, dmaster);
|
||||
ret = ctdb_ctrl_setdmaster(ctdb, timeval_current_ofs(timelimit, 0), vnn, ctdb, dbid, dmaster);
|
||||
if (ret != 0) {
|
||||
printf("Unable to set dmaster for node %u db:0x%08x\n", vnn, dbid);
|
||||
return ret;
|
||||
@ -694,10 +701,10 @@ static int control_createdb(struct ctdb_context *ctdb, int argc, const char **ar
|
||||
/* tell ctdb daemon to attach */
|
||||
data.dptr = discard_const(dbname);
|
||||
data.dsize = strlen(dbname)+1;
|
||||
timeout = timeval_current_ofs(1, 0);
|
||||
timeout = timeval_current_ofs(timelimit, 0);
|
||||
ret = ctdb_control(ctdb, vnn, 0, CTDB_CONTROL_DB_ATTACH,
|
||||
0, data, ctdb, &data, &res,
|
||||
&timeout);
|
||||
&timeout, NULL);
|
||||
if (ret != 0 || res != 0 || data.dsize != sizeof(uint32_t)) {
|
||||
DEBUG(0,("Failed to attach to database '%s'\n", dbname));
|
||||
return -1;
|
||||
@ -715,7 +722,7 @@ static int control_ping(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
uint32_t *nodes;
|
||||
uint32_t num_nodes;
|
||||
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(1, 0), ctdb, &num_nodes);
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(timelimit, 0), ctdb, &num_nodes);
|
||||
CTDB_NO_MEMORY(ctdb, nodes);
|
||||
|
||||
for (i=0;i<num_nodes;i++) {
|
||||
@ -742,7 +749,7 @@ static int control_debuglevel(struct ctdb_context *ctdb, int argc, const char **
|
||||
uint32_t *nodes;
|
||||
uint32_t num_nodes;
|
||||
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(1, 0), ctdb, &num_nodes);
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(timelimit, 0), ctdb, &num_nodes);
|
||||
CTDB_NO_MEMORY(ctdb, nodes);
|
||||
|
||||
for (i=0;i<num_nodes;i++) {
|
||||
@ -785,7 +792,7 @@ static int control_debug(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(1, 0), ctdb, &num_nodes);
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(timelimit, 0), ctdb, &num_nodes);
|
||||
CTDB_NO_MEMORY(ctdb, nodes);
|
||||
for (i=0;i<num_nodes;i++) {
|
||||
ret = ctdb_ctrl_set_debuglevel(ctdb, nodes[i], level);
|
||||
@ -799,6 +806,85 @@ static int control_debug(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
freeze a node
|
||||
*/
|
||||
static int control_freeze(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
{
|
||||
int ret=0, count=0;
|
||||
uint32_t vnn, i;
|
||||
uint32_t *nodes;
|
||||
uint32_t num_nodes;
|
||||
|
||||
if (argc < 1) {
|
||||
usage();
|
||||
}
|
||||
|
||||
if (strcmp(argv[0], "all") != 0) {
|
||||
vnn = strtoul(argv[0], NULL, 0);
|
||||
ret = ctdb_ctrl_freeze(ctdb, timeval_current_ofs(timelimit, 0), vnn);
|
||||
if (ret != 0) {
|
||||
printf("Unable to freeze node %u\n", vnn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(timelimit, 0), ctdb, &num_nodes);
|
||||
CTDB_NO_MEMORY(ctdb, nodes);
|
||||
for (i=0;i<num_nodes;i++) {
|
||||
int res = ctdb_ctrl_freeze(ctdb, timeval_current_ofs(timelimit, 0), nodes[i]);
|
||||
if (res != 0) {
|
||||
printf("Warning: Unable to freeze node %u\n", nodes[i]);
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
ret |= res;
|
||||
}
|
||||
printf("Froze %u nodes\n", count);
|
||||
talloc_free(nodes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
thaw a node
|
||||
*/
|
||||
static int control_thaw(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
{
|
||||
int ret=0, count=0;
|
||||
uint32_t vnn, i;
|
||||
uint32_t *nodes;
|
||||
uint32_t num_nodes;
|
||||
|
||||
if (argc < 1) {
|
||||
usage();
|
||||
}
|
||||
|
||||
if (strcmp(argv[0], "all") != 0) {
|
||||
vnn = strtoul(argv[0], NULL, 0);
|
||||
ret = ctdb_ctrl_thaw(ctdb, timeval_current_ofs(timelimit, 0), vnn);
|
||||
if (ret != 0) {
|
||||
printf("Unable to thaw node %u\n", vnn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
nodes = ctdb_get_connected_nodes(ctdb, timeval_current_ofs(timelimit, 0), ctdb, &num_nodes);
|
||||
CTDB_NO_MEMORY(ctdb, nodes);
|
||||
for (i=0;i<num_nodes;i++) {
|
||||
int res = ctdb_ctrl_thaw(ctdb, timeval_current_ofs(timelimit, 0), nodes[i]);
|
||||
if (res != 0) {
|
||||
printf("Warning: Unable to thaw node %u\n", nodes[i]);
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
ret |= res;
|
||||
}
|
||||
printf("Thawed %u nodes\n", count);
|
||||
talloc_free(nodes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
attach to a database
|
||||
*/
|
||||
@ -837,7 +923,7 @@ static int control_dumpmemory(struct ctdb_context *ctdb, int argc, const char **
|
||||
}
|
||||
|
||||
ctdb_control(ctdb, vnn, 0, CTDB_CONTROL_DUMP_MEMORY,
|
||||
CTDB_CTRL_FLAG_NOREPLY, tdb_null, NULL, NULL, NULL, NULL);
|
||||
CTDB_CTRL_FLAG_NOREPLY, tdb_null, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -851,6 +937,7 @@ int main(int argc, const char *argv[])
|
||||
struct poptOption popt_options[] = {
|
||||
POPT_AUTOHELP
|
||||
POPT_CTDB_CMDLINE
|
||||
{ "timelimit", 't', POPT_ARG_INT, &timelimit, 0, "timelimit", "integer" },
|
||||
POPT_TABLEEND
|
||||
};
|
||||
int opt;
|
||||
@ -886,6 +973,8 @@ int main(int argc, const char *argv[])
|
||||
{ "attach", control_attach },
|
||||
{ "dumpmemory", control_dumpmemory },
|
||||
{ "getpid", control_getpid },
|
||||
{ "freeze", control_freeze },
|
||||
{ "thaw", control_thaw },
|
||||
};
|
||||
|
||||
pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
|
||||
|
Reference in New Issue
Block a user