next step towards dmaster/lmaster code
authorAndrew Tridgell <tridge@samba.org>
Mon, 18 Dec 2006 03:05:49 +0000 (14:05 +1100)
committerAndrew Tridgell <tridge@samba.org>
Mon, 18 Dec 2006 03:05:49 +0000 (14:05 +1100)
(This used to be ctdb commit 95e7be8d1aaafafb574c406fe778093606a28be8)

ctdb/common/ctdb_call.c
ctdb/common/ctdb_ltdb.c
ctdb/include/ctdb_private.h
ctdb/tests/test1.sh

index 441e22b613c6df4a748808ef52e853e5b8e5a7a2..74d97ee5994b9dacf74156997870910790b37f3a 100644 (file)
 /*
   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);
index 004ab254d5d6aafc9ce6dda2601dc0f7f39973b8..821aad5ee59aef32804f97035a29f4c4a703ccc4 100644 (file)
@@ -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);
 
index bbddd74b589432b906c0b24e69bcd75262bbebab..8675dccaddfeea30699d7ff49cfe642b695b8051 100644 (file)
@@ -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);
index c91899fb38074c605b7a973285c80150fb76be80..26c6bc100275b3ccea05d5be3564d1024277470c 100755 (executable)
@@ -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