From: Andrew Tridgell Date: Mon, 18 Dec 2006 03:05:49 +0000 (+1100) Subject: next step towards dmaster/lmaster code X-Git-Tag: tevent-0.9.20~348^2~2999 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=abf3b910be64613a1b40522287b5ccb68ea75852;p=thirdparty%2Fsamba.git next step towards dmaster/lmaster code (This used to be ctdb commit 95e7be8d1aaafafb574c406fe778093606a28be8) --- diff --git a/ctdb/common/ctdb_call.c b/ctdb/common/ctdb_call.c index 441e22b613c..74d97ee5994 100644 --- a/ctdb/common/ctdb_call.c +++ b/ctdb/common/ctdb_call.c @@ -28,25 +28,20 @@ /* local version of ctdb_call */ -static int ctdb_call_local(struct ctdb_context *ctdb, TDB_DATA key, int call_id, - TDB_DATA *call_data, TDB_DATA *reply_data) +static int ctdb_call_local(struct ctdb_context *ctdb, TDB_DATA key, + struct ctdb_ltdb_header *header, TDB_DATA *data, + int call_id, TDB_DATA *call_data, TDB_DATA *reply_data) { struct ctdb_call *c; struct ctdb_registered_call *fn; - TDB_DATA data; - struct ctdb_ltdb_header header; - int ret; c = talloc(ctdb, struct ctdb_call); CTDB_NO_MEMORY(ctdb, c); - ret = ctdb_ltdb_fetch(ctdb, c, key, &header, &data); - if (ret != 0) return -1; - c->key = key; c->call_data = call_data; - c->record_data.dptr = talloc_memdup(c, data.dptr, data.dsize); - c->record_data.dsize = data.dsize; + c->record_data.dptr = talloc_memdup(c, data->dptr, data->dsize); + c->record_data.dsize = data->dsize; CTDB_NO_MEMORY(ctdb, c->record_data.dptr); c->new_data = NULL; c->reply_data = NULL; @@ -65,7 +60,7 @@ static int ctdb_call_local(struct ctdb_context *ctdb, TDB_DATA key, int call_id, } if (c->new_data) { - if (ctdb_ltdb_store(ctdb, key, &header, *c->new_data) != 0) { + if (ctdb_ltdb_store(ctdb, key, header, *c->new_data) != 0) { ctdb_set_error(ctdb, "ctdb_call tdb_store failed\n"); return -1; } @@ -86,22 +81,60 @@ static int ctdb_call_local(struct ctdb_context *ctdb, TDB_DATA key, int call_id, return 0; } +/* + send an error reply +*/ +static void ctdb_send_error(struct ctdb_context *ctdb, + struct ctdb_req_header *hdr, int ecode) +{ + printf("ctdb_send_error not implemented\n"); +} + +/* + send a redirect reply +*/ +static void ctdb_call_send_redirect(struct ctdb_context *ctdb, + struct ctdb_req_call *c, + struct ctdb_ltdb_header *header) +{ + printf("ctdb_call_send_redirect not implemented\n"); +} + /* called when a CTDB_REQ_CALL packet comes in */ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { struct ctdb_req_call *c = (struct ctdb_req_call *)hdr; - TDB_DATA key, call_data, reply_data; + TDB_DATA key, data, call_data, reply_data; struct ctdb_reply_call *r; struct ctdb_node *node; + int ret; + struct ctdb_ltdb_header header; key.dptr = c->data; key.dsize = c->keylen; call_data.dptr = c->data + c->keylen; call_data.dsize = c->calldatalen; - ctdb_call_local(ctdb, key, c->callid, + /* determine if we are the dmaster for this key. This also + fetches the record data (if any), thus avoiding a 2nd fetch of the data + if the call will be answered locally */ + ret = ctdb_ltdb_fetch(ctdb, key, &header, &data); + if (ret != 0) { + ctdb_send_error(ctdb, hdr, ret); + return; + } + + /* if we are not the dmaster, then send a redirect to the + requesting node */ + if (header.dmaster != ctdb->vnn) { + ctdb_call_send_redirect(ctdb, c, &header); + talloc_free(data.dptr); + return; + } + + ctdb_call_local(ctdb, key, &header, &data, c->callid, call_data.dsize?&call_data:NULL, &reply_data); @@ -181,7 +214,9 @@ void ctdb_call_timeout(struct event_context *ev, struct timed_event *te, */ struct ctdb_call_state *ctdb_call_local_send(struct ctdb_context *ctdb, TDB_DATA key, int call_id, - TDB_DATA *call_data, TDB_DATA *reply_data) + TDB_DATA *call_data, TDB_DATA *reply_data, + struct ctdb_ltdb_header *header, + TDB_DATA *data) { struct ctdb_call_state *state; int ret; @@ -192,7 +227,8 @@ struct ctdb_call_state *ctdb_call_local_send(struct ctdb_context *ctdb, state->state = CTDB_CALL_DONE; state->node = ctdb->nodes[ctdb->vnn]; - ret = ctdb_call_local(ctdb, key, call_id, call_data, &state->reply_data); + ret = ctdb_call_local(ctdb, key, header, data, + call_id, call_data, &state->reply_data); return state; } @@ -204,13 +240,24 @@ struct ctdb_call_state *ctdb_call_send(struct ctdb_context *ctdb, TDB_DATA key, int call_id, TDB_DATA *call_data, TDB_DATA *reply_data) { - uint32_t dest; uint32_t len; struct ctdb_call_state *state; + int ret; + struct ctdb_ltdb_header header; + TDB_DATA data; - dest = ctdb_hash(&key) % ctdb->num_nodes; - if (dest == ctdb->vnn && !(ctdb->flags & CTDB_FLAG_SELF_CONNECT)) { - return ctdb_call_local_send(ctdb, key, call_id, call_data, reply_data); + /* + if we are the dmaster for this key then we don't need to + send it off at all, we can bypass the network and handle it + locally. To find out if we are the dmaster we need to look + in our ltdb + */ + ret = ctdb_ltdb_fetch(ctdb, key, &header, &data); + if (ret != 0) return NULL; + + if (header.dmaster == ctdb->vnn && !(ctdb->flags & CTDB_FLAG_SELF_CONNECT)) { + return ctdb_call_local_send(ctdb, key, call_id, call_data, reply_data, + &header, &data); } state = talloc_zero(ctdb, struct ctdb_call_state); @@ -222,7 +269,7 @@ struct ctdb_call_state *ctdb_call_send(struct ctdb_context *ctdb, state->c->hdr.length = len; state->c->hdr.operation = CTDB_REQ_CALL; - state->c->hdr.destnode = dest; + state->c->hdr.destnode = header.dmaster; state->c->hdr.srcnode = ctdb->vnn; /* this limits us to 16k outstanding messages - not unreasonable */ state->c->hdr.reqid = idr_get_new(ctdb->idr, state, 0xFFFF); @@ -234,7 +281,7 @@ struct ctdb_call_state *ctdb_call_send(struct ctdb_context *ctdb, memcpy(&state->c->data[key.dsize], call_data->dptr, call_data->dsize); } - state->node = ctdb->nodes[dest]; + state->node = ctdb->nodes[header.dmaster]; state->state = CTDB_CALL_WAIT; talloc_set_destructor(state, ctdb_call_destructor); diff --git a/ctdb/common/ctdb_ltdb.c b/ctdb/common/ctdb_ltdb.c index 004ab254d5d..821aad5ee59 100644 --- a/ctdb/common/ctdb_ltdb.c +++ b/ctdb/common/ctdb_ltdb.c @@ -50,6 +50,7 @@ static void ltdb_initial_header(struct ctdb_context *ctdb, struct ctdb_ltdb_header *header) { header->rsn = 0; + /* initial dmaster is the lmaster */ header->dmaster = ctdb_hash(&key) % ctdb->num_nodes; header->laccessor = header->dmaster; header->lacount = 0; @@ -61,7 +62,7 @@ static void ltdb_initial_header(struct ctdb_context *ctdb, and returning the body of the record. A valid (initial) header is returned if the record is not present */ -int ctdb_ltdb_fetch(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, +int ctdb_ltdb_fetch(struct ctdb_context *ctdb, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA *data) { TDB_DATA rec; @@ -78,7 +79,7 @@ int ctdb_ltdb_fetch(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, *header = *(struct ctdb_ltdb_header *)rec.dptr; data->dsize = rec.dsize - sizeof(struct ctdb_ltdb_header); - data->dptr = talloc_memdup(mem_ctx, sizeof(struct ctdb_ltdb_header)+rec.dptr, + data->dptr = talloc_memdup(ctdb, sizeof(struct ctdb_ltdb_header)+rec.dptr, data->dsize); CTDB_NO_MEMORY(ctdb, data->dptr); diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index bbddd74b589..8675dccaddf 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -158,7 +158,7 @@ uint32_t ctdb_hash(TDB_DATA *key); void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); -int ctdb_ltdb_fetch(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, +int ctdb_ltdb_fetch(struct ctdb_context *ctdb, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA *data); int ctdb_ltdb_store(struct ctdb_context *ctdb, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data); diff --git a/ctdb/tests/test1.sh b/ctdb/tests/test1.sh index c91899fb380..26c6bc10027 100755 --- a/ctdb/tests/test1.sh +++ b/ctdb/tests/test1.sh @@ -1,5 +1,6 @@ #!/bin/sh -killall -q ctdb_test +echo "Testing local send" bin/ctdb_test --nlist tests/1node.txt --listen 127.0.0.1:9001 -killall ctdb_test +echo "Testing self connect" +bin/ctdb_test --nlist tests/1node.txt --listen 127.0.0.1:9001 --self-connect