s3-ctdb: Make use of CTDB_CONTROL_CHECK_SRVIDS
authorVolker Lendecke <vl@samba.org>
Mon, 31 Oct 2011 15:30:38 +0000 (16:30 +0100)
committerVolker Lendecke <vlendec@samba.org>
Wed, 30 Nov 2011 11:47:27 +0000 (12:47 +0100)
This should be a lot quicker than PROCESS_EXISTS followed by looking at
serverid.tdb

Autobuild-User: Volker Lendecke <vlendec@samba.org>
Autobuild-Date: Wed Nov 30 12:47:27 CET 2011 on sn-devel-104

source3/configure.in
source3/include/ctdbd_conn.h
source3/lib/ctdbd_conn.c
source3/lib/serverid.c

index 529b29b044766114d4762f4517ead91dd23e696b..46c98aa12ca0a4a0aea829de920cff58858f4763 100644 (file)
@@ -5547,6 +5547,29 @@ if test "x$have_cluster_support" = "xyes" ; then
        fi
 fi
 
+if test "x$have_cluster_support" = "xyes" ; then
+       AC_HAVE_DECL(CTDB_CONTROL_CHECK_SRVIDS,[
+       #include "confdefs.h"
+       #define NO_CONFIG_H
+       #include "replace.h"
+       #include "system/wait.h"
+       #include "system/network.h"
+       #include <talloc.h>
+       #include <tdb.h>
+       #include <ctdb.h>
+       #include <ctdb_private.h>
+       ])
+       if test x"$ac_cv_have_CTDB_CONTROL_CHECK_SRVIDS_decl" != x"yes"
+       then
+               if test "x$enable_old_ctdb" = "xyes" ; then
+                       AC_MSG_WARN([ignoring missing CHECK_SRVIDS (--enable-old-ctdb)])
+               else
+                       ctdb_broken="support for CHECK_SRVIDS control missing"
+                       have_cluster_support=no
+               fi
+       fi
+fi
+
 if test "x$have_cluster_support" = "xyes" ; then
        # In ctdb 1.0.57, ctdb_control_tcp was temporarily renamed
        # to ctdb_tcp_client.
index 1d52577fe8fd03ff92ccec8a45e82f10fe65b774..9a3c27cdb99ad9a0c4a57ef5295b85bcebe6bfca 100644 (file)
@@ -46,6 +46,9 @@ bool ctdbd_process_exists(struct ctdbd_connection *conn, uint32 vnn,
 bool ctdb_processes_exist(struct ctdbd_connection *conn,
                          const struct server_id *pids, int num_pids,
                          bool *results);
+bool ctdb_serverids_exist(struct ctdbd_connection *conn,
+                         const struct server_id *pids, unsigned num_pids,
+                         bool *results);
 
 char *ctdbd_dbpath(struct ctdbd_connection *conn,
                   TALLOC_CTX *mem_ctx, uint32_t db_id);
@@ -79,5 +82,6 @@ NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32 opcode,
                             int *cstatus);
 NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn);
 NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn);
+NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid);
 
 #endif /* _CTDBD_CONN_H */
index e0bdbd05a5f0bff8abb0a82b5908084db6828450..940d477da1b31dcd6b9826cd3b15ab67a19fa25a 100644 (file)
@@ -107,8 +107,7 @@ static void ctdb_packet_dump(struct ctdb_req_header *hdr)
 /*
  * Register a srvid with ctdbd
  */
-static NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn,
-                                   uint64_t srvid)
+NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid)
 {
 
        int cstatus;
@@ -1032,6 +1031,215 @@ fail:
        return result;
 }
 
+struct ctdb_vnn_list {
+       uint32_t vnn;
+       uint32_t reqid;
+       unsigned num_srvids;
+       unsigned num_filled;
+       uint64_t *srvids;
+       unsigned *pid_indexes;
+};
+
+/*
+ * Get a list of all vnns mentioned in a list of
+ * server_ids. vnn_indexes tells where in the vnns array we have to
+ * place the pids.
+ */
+static bool ctdb_collect_vnns(TALLOC_CTX *mem_ctx,
+                             const struct server_id *pids, unsigned num_pids,
+                             struct ctdb_vnn_list **pvnns,
+                             unsigned *pnum_vnns)
+{
+       struct ctdb_vnn_list *vnns = NULL;
+       unsigned *vnn_indexes = NULL;
+       unsigned i, num_vnns = 0;
+
+       vnn_indexes = talloc_array(mem_ctx, unsigned, num_pids);
+       if (vnn_indexes == NULL) {
+               goto fail;
+       }
+
+       for (i=0; i<num_pids; i++) {
+               unsigned j;
+               uint32_t vnn = pids[i].vnn;
+
+               for (j=0; j<num_vnns; j++) {
+                       if (vnn == vnns[j].vnn) {
+                               break;
+                       }
+               }
+               vnn_indexes[i] = j;
+
+               if (j < num_vnns) {
+                       /*
+                        * Already in the array
+                        */
+                       vnns[j].num_srvids += 1;
+                       continue;
+               }
+               vnns = talloc_realloc(mem_ctx, vnns, struct ctdb_vnn_list,
+                                     num_vnns+1);
+               if (vnns == NULL) {
+                       goto fail;
+               }
+               vnns[num_vnns].vnn = vnn;
+               vnns[num_vnns].num_srvids = 1;
+               vnns[num_vnns].num_filled = 0;
+               num_vnns += 1;
+       }
+       for (i=0; i<num_vnns; i++) {
+               struct ctdb_vnn_list *vnn = &vnns[i];
+
+               vnn->srvids = talloc_array(vnns, uint64_t, vnn->num_srvids);
+               if (vnn->srvids == NULL) {
+                       goto fail;
+               }
+               vnn->pid_indexes = talloc_array(vnns, unsigned,
+                                               vnn->num_srvids);
+               if (vnn->pid_indexes == NULL) {
+                       goto fail;
+               }
+       }
+       for (i=0; i<num_pids; i++) {
+               struct ctdb_vnn_list *vnn = &vnns[vnn_indexes[i]];
+               vnn->srvids[vnn->num_filled] = pids[i].unique_id;
+               vnn->pid_indexes[vnn->num_filled] = i;
+               vnn->num_filled += 1;
+       }
+
+       TALLOC_FREE(vnn_indexes);
+       *pvnns = vnns;
+       *pnum_vnns = num_vnns;
+       return true;
+fail:
+       TALLOC_FREE(vnns);
+       TALLOC_FREE(vnn_indexes);
+       return false;
+}
+
+bool ctdb_serverids_exist(struct ctdbd_connection *conn,
+                         const struct server_id *pids, unsigned num_pids,
+                         bool *results)
+{
+       unsigned i, num_received;
+       NTSTATUS status;
+       struct ctdb_vnn_list *vnns = NULL;
+       unsigned num_vnns;
+       bool result = false;
+
+       if (!ctdb_collect_vnns(talloc_tos(), pids, num_pids,
+                              &vnns, &num_vnns)) {
+               goto fail;
+       }
+
+       for (i=0; i<num_vnns; i++) {
+               struct ctdb_vnn_list *vnn = &vnns[i];
+               struct ctdb_req_control req;
+
+               vnn->reqid = ctdbd_next_reqid(conn);
+
+               ZERO_STRUCT(req);
+
+               DEBUG(10, ("Requesting VNN %d, reqid=%d, num_srvids=%u\n",
+                          (int)vnn->vnn, (int)vnn->reqid, vnn->num_srvids));
+
+               req.hdr.length = offsetof(struct ctdb_req_control, data);
+               req.hdr.ctdb_magic   = CTDB_MAGIC;
+               req.hdr.ctdb_version = CTDB_VERSION;
+               req.hdr.operation    = CTDB_REQ_CONTROL;
+               req.hdr.reqid        = vnn->reqid;
+               req.hdr.destnode     = vnn->vnn;
+               req.opcode           = CTDB_CONTROL_CHECK_SRVIDS;
+               req.srvid            = 0;
+               req.datalen          = sizeof(uint64_t) * vnn->num_srvids;
+               req.hdr.length      += req.datalen;
+               req.flags            = 0;
+
+               DEBUG(10, ("ctdbd_control: Sending ctdb packet\n"));
+               ctdb_packet_dump(&req.hdr);
+
+               status = ctdb_packet_send(
+                       conn->pkt, 2,
+                       data_blob_const(
+                               &req, offsetof(struct ctdb_req_control,
+                                              data)),
+                       data_blob_const(vnn->srvids, req.datalen));
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10, ("ctdb_packet_send failed: %s\n",
+                                  nt_errstr(status)));
+                       goto fail;
+               }
+       }
+
+       status = ctdb_packet_flush(conn->pkt);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("ctdb_packet_flush failed: %s\n",
+                          nt_errstr(status)));
+               goto fail;
+       }
+
+       num_received = 0;
+
+       while (num_received < num_vnns) {
+               struct ctdb_reply_control *reply = NULL;
+               struct ctdb_vnn_list *vnn;
+               uint32_t reqid;
+
+               status = ctdb_read_req(conn, 0, talloc_tos(), (void *)&reply);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10, ("ctdb_read_req failed: %s\n",
+                                  nt_errstr(status)));
+                       goto fail;
+               }
+
+               if (reply->hdr.operation != CTDB_REPLY_CONTROL) {
+                       DEBUG(10, ("Received invalid reply\n"));
+                       goto fail;
+               }
+
+               reqid = reply->hdr.reqid;
+
+               DEBUG(10, ("Received reqid %d\n", (int)reqid));
+
+               for (i=0; i<num_vnns; i++) {
+                       if (reqid == vnns[i].reqid) {
+                               break;
+                       }
+               }
+               if (i == num_vnns) {
+                       DEBUG(10, ("Received unknown reqid number %u\n",
+                                  (unsigned)reqid));
+                       goto fail;
+               }
+
+               DEBUG(10, ("Found index %u\n", i));
+
+               vnn = &vnns[i];
+
+               DEBUG(10, ("Received vnn %u, vnn->num_srvids %u, datalen %u\n",
+                          (unsigned)vnn->vnn, vnn->num_srvids,
+                          (unsigned)reply->datalen));
+
+               if (reply->datalen < ((vnn->num_srvids+7)/8)) {
+                       DEBUG(10, ("Received short reply\n"));
+                       goto fail;
+               }
+
+               for (i=0; i<vnn->num_srvids; i++) {
+                       results[vnn->pid_indexes[i]] =
+                               ((reply->data[i/8] & (1<<(i%8))) != 0);
+               }
+
+               TALLOC_FREE(reply);
+               num_received += 1;
+       }
+
+       result = true;
+fail:
+       TALLOC_FREE(vnns);
+       return result;
+}
+
 /*
  * Get a db path
  */
index 274b44b86fbabb36b3ea685ffeab795ae9486ce8..c1b87f79294a75f57bf6b26767b9d57b35805dba 100644 (file)
@@ -25,6 +25,8 @@
 #include "dbwrap/dbwrap_open.h"
 #include "lib/util/tdb_wrap.h"
 #include "lib/param/param.h"
+#include "ctdbd_conn.h"
+#include "messages.h"
 
 struct serverid_key {
        pid_t pid;
@@ -122,6 +124,11 @@ bool serverid_register(const struct server_id id, uint32_t msg_flags)
                          nt_errstr(status)));
                goto done;
        }
+#ifdef HAVE_CTDB_CONTROL_CHECK_SRVIDS_DECL
+       if (lp_clustering()) {
+               register_with_ctdbd(messaging_ctdbd_connection(), id.unique_id);
+       }
+#endif
        ret = true;
 done:
        TALLOC_FREE(rec);
@@ -278,6 +285,12 @@ bool serverids_exist(const struct server_id *ids, int num_ids, bool *results)
        struct db_context *db;
        int i;
 
+#ifdef HAVE_CTDB_CONTROL_CHECK_SRVIDS_DECL
+       if (lp_clustering()) {
+               return ctdb_serverids_exist(messaging_ctdbd_connection(),
+                                           ids, num_ids, results);
+       }
+#endif
        if (!processes_exist(ids, num_ids, results)) {
                return false;
        }