mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
merge from tridge
(This used to be ctdb commit 414952b2dd48de4a9edb532ba9c2cb6e22bb6d7f)
This commit is contained in:
commit
1812d787ac
@ -10,3 +10,7 @@ config.h
|
||||
config.h.in
|
||||
nodes-ssh.txt
|
||||
TAGS
|
||||
ctdb-0
|
||||
ctdb-1
|
||||
ctdb-2
|
||||
ctdb-3
|
||||
|
@ -31,11 +31,13 @@ static struct {
|
||||
const char *transport;
|
||||
const char *myaddress;
|
||||
int self_connect;
|
||||
const char *db_dir;
|
||||
} ctdb_cmdline = {
|
||||
.nlist = NULL,
|
||||
.transport = "tcp",
|
||||
.myaddress = NULL,
|
||||
.self_connect = 0,
|
||||
.db_dir = NULL
|
||||
};
|
||||
|
||||
|
||||
@ -45,6 +47,7 @@ struct poptOption popt_ctdb_cmdline[] = {
|
||||
{ "transport", 0, POPT_ARG_STRING, &ctdb_cmdline.transport, 0, "protocol transport", NULL },
|
||||
{ "self-connect", 0, POPT_ARG_NONE, &ctdb_cmdline.self_connect, 0, "enable self connect", "boolean" },
|
||||
{ "debug", 'd', POPT_ARG_INT, &LogLevel, 0, "debug level"},
|
||||
{ "dbdir", 0, POPT_ARG_STRING, &ctdb_cmdline.db_dir, 0, "directory for the tdb files", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -93,5 +96,11 @@ struct ctdb_context *ctdb_cmdline_init(struct event_context *ev)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = ctdb_set_tdb_dir(ctdb, ctdb_cmdline.db_dir);
|
||||
if (ret == -1) {
|
||||
printf("ctdb_set_tdb_dir failed - %s\n", ctdb_errstr(ctdb));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return ctdb;
|
||||
}
|
||||
|
@ -73,6 +73,22 @@ void ctdb_set_max_lacount(struct ctdb_context *ctdb, unsigned count)
|
||||
ctdb->max_lacount = count;
|
||||
}
|
||||
|
||||
/*
|
||||
set the directory for the local databases
|
||||
*/
|
||||
int ctdb_set_tdb_dir(struct ctdb_context *ctdb, const char *dir)
|
||||
{
|
||||
if (dir == NULL) {
|
||||
ctdb->db_directory = talloc_asprintf(ctdb, "ctdb-%u", ctdb_get_vnn(ctdb));
|
||||
} else {
|
||||
ctdb->db_directory = talloc_strdup(ctdb, dir);
|
||||
}
|
||||
if (ctdb->db_directory == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
add a node to the list of active nodes
|
||||
*/
|
||||
|
@ -487,8 +487,7 @@ void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
|
||||
and data */
|
||||
state->header.dmaster = ctdb->vnn;
|
||||
|
||||
if (!state->fetch_private &&
|
||||
ctdb_ltdb_store(ctdb_db, state->call.key, &state->header, data) != 0) {
|
||||
if (ctdb_ltdb_store(ctdb_db, state->call.key, &state->header, data) != 0) {
|
||||
ctdb_fatal(ctdb, "ctdb_reply_dmaster store failed\n");
|
||||
return;
|
||||
}
|
||||
|
@ -463,10 +463,13 @@ static int ctdb_fetch_lock_destructor(struct ctdb_fetch_lock_state *state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
send a fetch lock request from the client to the daemon. This just asks for
|
||||
a record migration to the current node
|
||||
*/
|
||||
static struct ctdb_fetch_lock_state *ctdb_client_fetch_lock_send(struct ctdb_db_context *ctdb_db,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
TDB_DATA key,
|
||||
struct ctdb_ltdb_header *header)
|
||||
TDB_DATA key)
|
||||
{
|
||||
struct ctdb_fetch_lock_state *state;
|
||||
struct ctdb_context *ctdb = ctdb_db->ctdb;
|
||||
@ -502,7 +505,6 @@ static struct ctdb_fetch_lock_state *ctdb_client_fetch_lock_send(struct ctdb_db_
|
||||
req->hdr.reqid = idr_get_new(ctdb->idr, state, 0xFFFF);
|
||||
req->db_id = ctdb_db->db_id;
|
||||
req->keylen = key.dsize;
|
||||
req->header = *header;
|
||||
memcpy(&req->key[0], key.dptr, key.dsize);
|
||||
|
||||
talloc_set_destructor(state, ctdb_fetch_lock_destructor);
|
||||
@ -522,8 +524,7 @@ static struct ctdb_fetch_lock_state *ctdb_client_fetch_lock_send(struct ctdb_db_
|
||||
This is called when the program wants to wait for a ctdb_fetch_lock to complete and get the
|
||||
results. This call will block unless the call has already completed.
|
||||
*/
|
||||
int ctdb_client_fetch_lock_recv(struct ctdb_fetch_lock_state *state, TALLOC_CTX *mem_ctx,
|
||||
TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA *data)
|
||||
int ctdb_client_fetch_lock_recv(struct ctdb_fetch_lock_state *state)
|
||||
{
|
||||
while (state->state < CTDB_FETCH_LOCK_DONE) {
|
||||
event_loop_once(state->ctdb_db->ctdb->ev);
|
||||
@ -532,13 +533,7 @@ int ctdb_client_fetch_lock_recv(struct ctdb_fetch_lock_state *state, TALLOC_CTX
|
||||
talloc_free(state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*header = state->r->header;
|
||||
data->dsize = state->r->datalen;
|
||||
data->dptr = talloc_memdup(mem_ctx, state->r->data, data->dsize);
|
||||
|
||||
talloc_free(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -569,8 +564,7 @@ struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db, TALL
|
||||
3) if we are the dmaster then return handle
|
||||
4) if not dmaster then ask ctdb daemon to make us dmaster, and wait for
|
||||
reply from ctdbd
|
||||
5) when we get the reply, we are now dmaster, update vnn in header
|
||||
6) return handle
|
||||
5) when we get the reply, goto (1)
|
||||
*/
|
||||
|
||||
h = talloc_zero(mem_ctx, struct ctdb_record_handle);
|
||||
@ -590,6 +584,7 @@ struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db, TALL
|
||||
DEBUG(3,("ctdb_fetch_lock: key=%*.*s\n", key.dsize, key.dsize,
|
||||
(const char *)key.dptr));
|
||||
|
||||
again:
|
||||
/* step 1 - get the chain lock */
|
||||
ret = ctdb_ltdb_lock(ctdb_db, key);
|
||||
if (ret != 0) {
|
||||
@ -604,44 +599,28 @@ struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db, TALL
|
||||
|
||||
ret = ctdb_ltdb_fetch(ctdb_db, key, &h->header, h, data);
|
||||
if (ret != 0) {
|
||||
ctdb_ltdb_unlock(ctdb_db, key);
|
||||
talloc_free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG(4,("ctdb_fetch_lock: done local fetch\n"));
|
||||
|
||||
/* step 2 - check if we are the dmaster */
|
||||
if (h->header.dmaster == ctdb_db->ctdb->vnn) {
|
||||
DEBUG(4,("ctdb_fetch_lock: we are dmaster - done\n"));
|
||||
return h;
|
||||
if (h->header.dmaster != ctdb_db->ctdb->vnn) {
|
||||
/* we're not the dmaster - ask the ctdb daemon to make us dmaster */
|
||||
state = ctdb_client_fetch_lock_send(ctdb_db, mem_ctx, key);
|
||||
ctdb_ltdb_unlock(ctdb_db, key);
|
||||
DEBUG(4,("ctdb_fetch_lock: done fetch_lock_send\n"));
|
||||
ret = ctdb_client_fetch_lock_recv(state);
|
||||
if (ret != 0) {
|
||||
DEBUG(4,("ctdb_fetch_lock: fetch_lock_recv failed\n"));
|
||||
talloc_free(h);
|
||||
return NULL;
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* we're not the dmaster - ask the ctdb daemon to make us dmaster */
|
||||
state = ctdb_client_fetch_lock_send(ctdb_db, mem_ctx, key, &h->header);
|
||||
DEBUG(4,("ctdb_fetch_lock: done fetch_lock_send\n"));
|
||||
ret = ctdb_client_fetch_lock_recv(state, mem_ctx, key, &h->header, data);
|
||||
if (ret != 0) {
|
||||
DEBUG(4,("ctdb_fetch_lock: fetch_lock_recv failed\n"));
|
||||
talloc_free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG(4,("ctdb_fetch_lock: record is now local\n"));
|
||||
|
||||
/* the record is now local, and locked. update the record on disk
|
||||
to mark us as the dmaster*/
|
||||
h->header.dmaster = ctdb_db->ctdb->vnn;
|
||||
ret = ctdb_ltdb_store(ctdb_db, key, &h->header, *data);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, (__location__" can't update record to mark us as dmaster\n"));
|
||||
talloc_free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG(4,("ctdb_fetch_lock: done\n"));
|
||||
|
||||
/* give the caller a handle to be used for ctdb_record_store() or a cancel via
|
||||
a talloc_free() */
|
||||
DEBUG(4,("ctdb_fetch_lock: we are dmaster - done\n"));
|
||||
return h;
|
||||
}
|
||||
|
||||
|
@ -124,6 +124,9 @@ static void daemon_request_register_message_handler(struct ctdb_client *client,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
send a fetch lock request (actually a ctdb_call()) to a remote node
|
||||
*/
|
||||
static struct ctdb_call_state *ctdb_daemon_fetch_lock_send(struct ctdb_db_context *ctdb_db,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
TDB_DATA key, struct ctdb_ltdb_header *header,
|
||||
@ -156,42 +159,6 @@ static struct ctdb_call_state *ctdb_daemon_fetch_lock_send(struct ctdb_db_contex
|
||||
return state;
|
||||
}
|
||||
|
||||
struct client_fetch_lock_data {
|
||||
struct ctdb_client *client;
|
||||
uint32_t reqid;
|
||||
};
|
||||
|
||||
static void daemon_fetch_lock_complete(struct ctdb_call_state *state)
|
||||
{
|
||||
struct ctdb_reply_fetch_lock *r;
|
||||
struct client_fetch_lock_data *data = talloc_get_type(state->async.private_data, struct client_fetch_lock_data);
|
||||
struct ctdb_client *client = talloc_get_type(data->client, struct ctdb_client);
|
||||
int length, res;
|
||||
|
||||
length = offsetof(struct ctdb_reply_fetch_lock, data) + state->call.reply_data.dsize;
|
||||
r = ctdbd_allocate_pkt(client->ctdb, length);
|
||||
if (r == NULL) {
|
||||
DEBUG(0,(__location__ " Failed to allocate reply_call in ctdb daemon\n"));
|
||||
return;
|
||||
}
|
||||
memset(r, 0, offsetof(struct ctdb_reply_fetch_lock, data));
|
||||
r->hdr.length = length;
|
||||
r->hdr.ctdb_magic = CTDB_MAGIC;
|
||||
r->hdr.ctdb_version = CTDB_VERSION;
|
||||
r->hdr.operation = CTDB_REPLY_FETCH_LOCK;
|
||||
r->hdr.reqid = data->reqid;
|
||||
r->state = state->state;
|
||||
r->datalen = state->call.reply_data.dsize;
|
||||
memcpy(&r->data[0], state->call.reply_data.dptr, r->datalen);
|
||||
|
||||
res = ctdb_queue_send(client->queue, (uint8_t *)&r->hdr, r->hdr.length);
|
||||
if (res != 0) {
|
||||
DEBUG(0,(__location__ " Failed to queue packet from daemon to client\n"));
|
||||
}
|
||||
talloc_free(r);
|
||||
talloc_free(state);
|
||||
}
|
||||
|
||||
/*
|
||||
called when the daemon gets a shutdown request from a client
|
||||
*/
|
||||
@ -246,11 +213,17 @@ static void daemon_request_shutdown(struct ctdb_client *client,
|
||||
}
|
||||
|
||||
|
||||
struct client_fetch_lock_data {
|
||||
struct ctdb_client *client;
|
||||
struct ctdb_req_fetch_lock *f;
|
||||
};
|
||||
|
||||
/*
|
||||
send a fetch lock error reply to the client
|
||||
*/
|
||||
static void daemon_fetch_lock_error(struct ctdb_client *client,
|
||||
struct ctdb_req_fetch_lock *f)
|
||||
static void daemon_fetch_lock_reply(struct ctdb_client *client,
|
||||
struct ctdb_req_fetch_lock *f,
|
||||
int state)
|
||||
{
|
||||
struct ctdb_reply_fetch_lock r;
|
||||
|
||||
@ -260,15 +233,26 @@ static void daemon_fetch_lock_error(struct ctdb_client *client,
|
||||
r.hdr.ctdb_version = CTDB_VERSION;
|
||||
r.hdr.operation = CTDB_REPLY_FETCH_LOCK;
|
||||
r.hdr.reqid = f->hdr.reqid;
|
||||
r.state = -1;
|
||||
r.state = state;
|
||||
|
||||
/*
|
||||
* Ignore the result, there's not much we can do anyway.
|
||||
*/
|
||||
ctdb_queue_send(client->queue, (uint8_t *)&r.hdr,
|
||||
r.hdr.length);
|
||||
ctdb_queue_send(client->queue, (uint8_t *)&r.hdr, r.hdr.length);
|
||||
}
|
||||
|
||||
/*
|
||||
called when a remote fetch lock finishes
|
||||
*/
|
||||
static void daemon_fetch_lock_complete(struct ctdb_call_state *state)
|
||||
{
|
||||
struct client_fetch_lock_data *data = talloc_get_type(state->async.private_data,
|
||||
struct client_fetch_lock_data);
|
||||
struct ctdb_client *client = talloc_get_type(data->client, struct ctdb_client);
|
||||
|
||||
daemon_fetch_lock_reply(client, data->f, 0);
|
||||
talloc_free(state);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
called when the daemon gets a fetch lock request from a client
|
||||
*/
|
||||
@ -279,32 +263,43 @@ static void daemon_request_fetch_lock(struct ctdb_client *client,
|
||||
TDB_DATA key, *data;
|
||||
struct ctdb_db_context *ctdb_db;
|
||||
struct client_fetch_lock_data *fl_data;
|
||||
struct ctdb_ltdb_header header;
|
||||
int ret;
|
||||
|
||||
ctdb_db = find_ctdb_db(client->ctdb, f->db_id);
|
||||
if (ctdb_db == NULL) {
|
||||
daemon_fetch_lock_error(client, f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctdb_validate_vnn(client->ctdb, f->header.dmaster)) {
|
||||
DEBUG(0,(__location__ " Invalid dmaster %u\n", f->header.dmaster));
|
||||
daemon_fetch_lock_error(client, f);
|
||||
daemon_fetch_lock_reply(client, f, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
key.dsize = f->keylen;
|
||||
key.dptr = &f->key[0];
|
||||
|
||||
/* XXX - needs non-blocking lock here */
|
||||
|
||||
ret = ctdb_ltdb_fetch(ctdb_db, key, &header, ctdb_db, NULL);
|
||||
if (ret != 0) {
|
||||
daemon_fetch_lock_reply(client, f, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (header.dmaster == ctdb_db->ctdb->vnn) {
|
||||
/* we already are the dmaster */
|
||||
daemon_fetch_lock_reply(client, f, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
data = talloc(client, TDB_DATA);
|
||||
data->dptr = NULL;
|
||||
data->dsize = 0;
|
||||
|
||||
state = ctdb_daemon_fetch_lock_send(ctdb_db, client, key, &f->header, data);
|
||||
state = ctdb_daemon_fetch_lock_send(ctdb_db, client, key, &header, data);
|
||||
talloc_steal(state, data);
|
||||
|
||||
fl_data = talloc(state, struct client_fetch_lock_data);
|
||||
fl_data->client = client;
|
||||
fl_data->reqid = f->hdr.reqid;
|
||||
fl_data->f = talloc_steal(fl_data, f);
|
||||
|
||||
state->async.fn = daemon_fetch_lock_complete;
|
||||
state->async.private_data = fl_data;
|
||||
}
|
||||
@ -477,12 +472,15 @@ static void daemon_incoming_packet(struct ctdb_client *client, void *data, size_
|
||||
case CTDB_REQ_CONNECT_WAIT:
|
||||
daemon_request_connect_wait(client, (struct ctdb_req_connect_wait *)hdr);
|
||||
break;
|
||||
|
||||
case CTDB_REQ_FETCH_LOCK:
|
||||
daemon_request_fetch_lock(client, (struct ctdb_req_fetch_lock *)hdr);
|
||||
break;
|
||||
|
||||
case CTDB_REQ_SHUTDOWN:
|
||||
daemon_request_shutdown(client, (struct ctdb_req_shutdown *)hdr);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG(0,(__location__ " daemon: unrecognized operation %d\n",
|
||||
hdr->operation));
|
||||
|
@ -82,14 +82,21 @@ struct ctdb_db_context *ctdb_attach(struct ctdb_context *ctdb, const char *name,
|
||||
}
|
||||
}
|
||||
|
||||
if (mkdir(ctdb->db_directory, 0700) == -1 && errno != EEXIST) {
|
||||
DEBUG(0,(__location__ " Unable to create ctdb directory '%s'\n",
|
||||
ctdb->db_directory));
|
||||
talloc_free(ctdb_db);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* add the node id to the database name, so when we run on loopback
|
||||
we don't conflict in the local filesystem */
|
||||
name = talloc_asprintf(ctdb_db, "%s.%u", name, ctdb_get_vnn(ctdb));
|
||||
name = talloc_asprintf(ctdb_db, "%s/%s", ctdb->db_directory, name);
|
||||
|
||||
/* when we have a separate daemon this will need to be a real
|
||||
file, not a TDB_INTERNAL, so the parent can access it to
|
||||
for ltdb bypass */
|
||||
ctdb_db->ltdb = tdb_wrap_open(ctdb, name, 0, TDB_DEFAULT, open_flags, mode);
|
||||
ctdb_db->ltdb = tdb_wrap_open(ctdb, name, 0, TDB_CLEAR_IF_FIRST, open_flags, mode);
|
||||
if (ctdb_db->ltdb == NULL) {
|
||||
ctdb_set_error(ctdb, "Failed to open tdb %s\n", name);
|
||||
talloc_free(ctdb_db);
|
||||
|
@ -71,6 +71,11 @@ struct ctdb_context *ctdb_init(struct event_context *ev);
|
||||
*/
|
||||
int ctdb_set_transport(struct ctdb_context *ctdb, const char *transport);
|
||||
|
||||
/*
|
||||
set the directory for the local databases
|
||||
*/
|
||||
int ctdb_set_tdb_dir(struct ctdb_context *ctdb, const char *dir);
|
||||
|
||||
/*
|
||||
set some flags
|
||||
*/
|
||||
|
@ -119,6 +119,7 @@ struct ctdb_context {
|
||||
struct event_context *ev;
|
||||
struct ctdb_address address;
|
||||
const char *name;
|
||||
const char *db_directory;
|
||||
uint32_t vnn; /* our own vnn */
|
||||
uint32_t num_nodes;
|
||||
uint32_t num_connected;
|
||||
@ -322,7 +323,6 @@ struct ctdb_reply_connect_wait {
|
||||
|
||||
struct ctdb_req_fetch_lock {
|
||||
struct ctdb_req_header hdr;
|
||||
struct ctdb_ltdb_header header;
|
||||
uint32_t db_id;
|
||||
uint32_t keylen;
|
||||
uint8_t key[1]; /* key[] */
|
||||
@ -331,9 +331,6 @@ struct ctdb_req_fetch_lock {
|
||||
struct ctdb_reply_fetch_lock {
|
||||
struct ctdb_req_header hdr;
|
||||
uint32_t state;
|
||||
struct ctdb_ltdb_header header;
|
||||
uint32_t datalen;
|
||||
uint8_t data[1]; /* data[] */
|
||||
};
|
||||
|
||||
/* internal prototypes */
|
||||
@ -460,4 +457,6 @@ struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctd
|
||||
struct ctdb_call *call,
|
||||
struct ctdb_ltdb_header *header);
|
||||
|
||||
void ctdb_request_finished(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user