1
0
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:
Ronnie Sahlberg
2007-05-14 06:25:15 +10:00
15 changed files with 795 additions and 316 deletions

View File

@ -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

View File

@ -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;

View File

@ -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"));
}
/*

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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
View 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;
}

View File

@ -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) {

View File

@ -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, &params);
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;

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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);

View File

@ -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);