summaryrefslogtreecommitdiffstats
path: root/ctdb
diff options
context:
space:
mode:
authorRonnie Sahlberg <ronniesahlberg@gmail.com>2012-02-08 15:29:27 +1100
committerRonnie Sahlberg <ronniesahlberg@gmail.com>2012-02-08 15:29:27 +1100
commit73f8be16c613a3767c44e29dab9b1d328a04e272 (patch)
tree3f2faf890f71deb76815b5f5dd17480a2527ec45 /ctdb
parent1eafa68f0f3b63dda173d939ed9e4882872b3bea (diff)
downloadsamba-73f8be16c613a3767c44e29dab9b1d328a04e272.tar.gz
samba-73f8be16c613a3767c44e29dab9b1d328a04e272.tar.xz
samba-73f8be16c613a3767c44e29dab9b1d328a04e272.zip
ReadOnly: add per-database statistics to view how much delegations/revokes we have
(This used to be ctdb commit 751ed46197661eb841042ab6a02855a51dd0b17c)
Diffstat (limited to 'ctdb')
-rw-r--r--ctdb/include/ctdb.h57
-rw-r--r--ctdb/include/ctdb_private.h11
-rw-r--r--ctdb/include/ctdb_protocol.h9
-rw-r--r--ctdb/libctdb/control.c51
-rw-r--r--ctdb/libctdb/sync.c18
-rw-r--r--ctdb/server/ctdb_call.c2
-rw-r--r--ctdb/server/ctdb_control.c4
-rw-r--r--ctdb/server/ctdb_daemon.c1
-rw-r--r--ctdb/server/ctdb_ltdb_server.c17
-rw-r--r--ctdb/tests/src/libctdb_test.c17
-rw-r--r--ctdb/tools/ctdb.c50
11 files changed, 237 insertions, 0 deletions
diff --git a/ctdb/include/ctdb.h b/ctdb/include/ctdb.h
index 8dbdd47e1e..93224cbdaa 100644
--- a/ctdb/include/ctdb.h
+++ b/ctdb/include/ctdb.h
@@ -510,6 +510,39 @@ bool ctdb_getpnn_recv(struct ctdb_connection *ctdb,
/**
+ * ctdb_getdbstat_send - read statistics for a db
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @db_id: the database to collect the statistics from
+ * @callback: the callback when ctdb replies to our message (typesafe)
+ * @cbdata: the argument to callback()
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ */
+struct ctdb_request *
+ctdb_getdbstat_send(struct ctdb_connection *ctdb,
+ uint32_t destnode,
+ uint32_t db_id,
+ ctdb_callback_t callback,
+ void *cbdata);
+/**
+ * ctdb_getdbstat_recv - read an ctdb_getdbstat reply from ctdbd
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @req: the completed request.
+ * @stat: a pointer to the *stat to fill in
+ *
+ * This returns false if something went wrong, or otherwise fills in **stats
+ * stats must be freed later by calling ctdb_free_dbstat();
+ */
+bool ctdb_getdbstat_recv(struct ctdb_connection *ctdb,
+ struct ctdb_request *req,
+ struct ctdb_db_statistics **stat);
+
+void ctdb_free_dbstat(struct ctdb_db_statistics *stat);
+
+/**
* ctdb_check_message_handlers_send - check a list of message_handlers
* if they are registered
* message_handlers are registered on the daemon using the
@@ -876,6 +909,26 @@ bool ctdb_getpnn(struct ctdb_connection *ctdb,
uint32_t *pnn);
/**
+ * ctdb_getdbstat - read the db stat of a node (synchronous)
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @db_id: the database to collect the statistics from
+ * @stat: a pointer to the *stat to fill in
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ *
+ * This returns false if something went wrong, or otherwise fills in **stat
+ * stat must be freed later by calling ctdb_free_dbstat();
+ */
+bool ctdb_getdbstat(struct ctdb_connection *ctdb,
+ uint32_t destnode,
+ uint32_t db_id,
+ struct ctdb_db_statistics **stat);
+
+
+/**
* ctdb_check_message_handlers - check a list of message_handlers (synchronous)
* @ctdb: the ctdb_connection from ctdb_connect.
* @destnode: the destination node (see below)
@@ -1092,6 +1145,10 @@ void ctdb_free_vnnmap(struct ctdb_vnn_map *vnnmap);
ctdb_getpnn_send((ctdb), (destnode), \
ctdb_sendcb((cb), (cbdata)), (cbdata))
+#define ctdb_getdbstat_send(ctdb, destnode, db_id, cb, cbdata) \
+ ctdb_getdbstat_send((ctdb), (destnode), (db_id), \
+ ctdb_sendcb((cb), (cbdata)), (cbdata))
+
#define ctdb_check_message_handlers_send(ctdb, destnode, num, mhs, \
cb, cbdata) \
ctdb_check_message_handlers_send((ctdb), (destnode), (num), \
diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h
index f58356fbe7..f420e6c341 100644
--- a/ctdb/include/ctdb_private.h
+++ b/ctdb/include/ctdb_private.h
@@ -300,6 +300,11 @@ struct ctdb_daemon_data {
ctdb->statistics_current.counter++; \
}
+#define CTDB_INCREMENT_DB_STAT(ctdb_db, counter) \
+ { \
+ ctdb_db->statistics.counter++; \
+ }
+
#define CTDB_DECREMENT_STAT(ctdb, counter) \
{ \
if (ctdb->statistics.counter > 0) \
@@ -513,6 +518,8 @@ struct ctdb_db_context {
so we can avoid sending duplicate fetch requests
*/
struct trbt_tree *deferred_fetch;
+
+ struct ctdb_db_statistics statistics;
};
@@ -1440,4 +1447,8 @@ int ctdb_fetch_func(struct ctdb_call_info *call);
int ctdb_fetch_with_header_func(struct ctdb_call_info *call);
+int32_t ctdb_control_get_db_statistics(struct ctdb_context *ctdb,
+ uint32_t db_id,
+ TDB_DATA *outdata);
+
#endif
diff --git a/ctdb/include/ctdb_protocol.h b/ctdb/include/ctdb_protocol.h
index 9cdf91c8d4..4cf27893ff 100644
--- a/ctdb/include/ctdb_protocol.h
+++ b/ctdb/include/ctdb_protocol.h
@@ -377,6 +377,7 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0,
CTDB_CONTROL_SET_DB_READONLY = 129,
CTDB_CONTROL_CHECK_SRVIDS = 130,
CTDB_CONTROL_TRAVERSE_START_EXT = 131,
+ CTDB_CONTROL_GET_DB_STATISTICS = 132,
};
/*
@@ -659,6 +660,14 @@ struct ctdb_statistics_wire {
};
/*
+ * db statistics
+ */
+struct ctdb_db_statistics {
+ uint32_t db_ro_delegations;
+ uint32_t db_ro_revokes;
+};
+
+/*
* wire format for interface list
*/
#ifdef IFNAMSIZ
diff --git a/ctdb/libctdb/control.c b/ctdb/libctdb/control.c
index ba22444ee5..8741ad9c0b 100644
--- a/ctdb/libctdb/control.c
+++ b/ctdb/libctdb/control.c
@@ -25,6 +25,7 @@
#undef ctdb_getrecmaster_send
#undef ctdb_getrecmode_send
#undef ctdb_getpnn_send
+#undef ctdb_getdbstat_send
#undef ctdb_check_message_handlers_send
#undef ctdb_getnodemap_send
#undef ctdb_getpublicips_send
@@ -112,6 +113,56 @@ struct ctdb_request *ctdb_getpnn_send(struct ctdb_connection *ctdb,
NULL, 0, callback, private_data);
}
+bool ctdb_getdbstat_recv(struct ctdb_connection *ctdb,
+ struct ctdb_request *req,
+ struct ctdb_db_statistics **stat)
+{
+ struct ctdb_reply_control *reply;
+ struct ctdb_db_statistics *s;
+
+ reply = unpack_reply_control(req, CTDB_CONTROL_GET_DB_STATISTICS);
+ if (!reply) {
+ return false;
+ }
+ if (reply->status == -1) {
+ DEBUG(ctdb, LOG_ERR, "ctdb_getpnn_recv: status -1");
+ return false;
+ }
+ if (reply->datalen != sizeof(struct ctdb_db_statistics)) {
+ DEBUG(ctdb, LOG_ERR, "ctdb_getdbstat_recv: returned data is %d bytes but should be %d", reply->datalen, (int)sizeof(struct ctdb_db_statistics));
+ return false;
+ }
+
+ s = malloc(sizeof(struct ctdb_db_statistics));
+ if (!s) {
+ return false;
+ }
+ memcpy(s, reply->data, sizeof(struct ctdb_db_statistics));
+ *stat = s;
+
+ return true;
+}
+
+struct ctdb_request *ctdb_getdbstat_send(struct ctdb_connection *ctdb,
+ uint32_t destnode,
+ uint32_t db_id,
+ ctdb_callback_t callback,
+ void *private_data)
+{
+ uint32_t indata = db_id;
+
+ return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_DB_STATISTICS, destnode,
+ &indata, sizeof(indata), callback, private_data);
+}
+
+void ctdb_free_dbstat(struct ctdb_db_statistics *stat)
+{
+ if (stat == NULL) {
+ return;
+ }
+ free(stat);
+}
+
bool ctdb_getnodemap_recv(struct ctdb_connection *ctdb,
struct ctdb_request *req, struct ctdb_node_map **nodemap)
{
diff --git a/ctdb/libctdb/sync.c b/ctdb/libctdb/sync.c
index f2b6957078..4b68cd1e32 100644
--- a/ctdb/libctdb/sync.c
+++ b/ctdb/libctdb/sync.c
@@ -136,6 +136,24 @@ bool ctdb_getpnn(struct ctdb_connection *ctdb,
return ret;
}
+bool ctdb_getdbstat(struct ctdb_connection *ctdb,
+ uint32_t destnode, uint32_t db_id,
+ struct ctdb_db_statistics **stat)
+{
+ struct ctdb_request *req;
+ bool done = false;
+ bool ret = false;
+
+ req = synchronous(ctdb,
+ ctdb_getdbstat_send(ctdb, destnode, db_id, set, &done),
+ &done);
+ if (req != NULL) {
+ ret = ctdb_getdbstat_recv(ctdb, req, stat);
+ ctdb_request_free(req);
+ }
+ return ret;
+}
+
bool ctdb_check_message_handlers(struct ctdb_connection *ctdb,
uint32_t destnode, uint32_t num,
uint64_t *mhs, uint8_t *result)
diff --git a/ctdb/server/ctdb_call.c b/ctdb/server/ctdb_call.c
index 8856f2ac28..9922233690 100644
--- a/ctdb/server/ctdb_call.c
+++ b/ctdb/server/ctdb_call.c
@@ -514,6 +514,7 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
if (header.flags & CTDB_REC_RO_REVOKE_COMPLETE) {
header.flags &= ~(CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY|CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_REVOKE_COMPLETE);
CTDB_INCREMENT_STAT(ctdb, total_ro_revokes);
+ CTDB_INCREMENT_DB_STAT(ctdb_db, db_ro_revokes);
if (ctdb_ltdb_store(ctdb_db, call->key, &header, data) != 0) {
ctdb_fatal(ctdb, "Failed to write header with cleared REVOKE flag");
}
@@ -621,6 +622,7 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
ctdb_queue_packet(ctdb, &r->hdr);
CTDB_INCREMENT_STAT(ctdb, total_ro_delegations);
+ CTDB_INCREMENT_DB_STAT(ctdb_db, db_ro_delegations);
talloc_free(r);
return;
diff --git a/ctdb/server/ctdb_control.c b/ctdb/server/ctdb_control.c
index 060f2c5cf3..c73458825c 100644
--- a/ctdb/server/ctdb_control.c
+++ b/ctdb/server/ctdb_control.c
@@ -630,6 +630,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
CHECK_CONTROL_DATA_SIZE(size);
return ctdb_control_schedule_for_deletion(ctdb, indata);
}
+ case CTDB_CONTROL_GET_DB_STATISTICS:
+ CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+ return ctdb_control_get_db_statistics(ctdb, *(uint32_t *)indata.dptr, outdata);
+
default:
DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
return -1;
diff --git a/ctdb/server/ctdb_daemon.c b/ctdb/server/ctdb_daemon.c
index bff91c5fa6..2436997864 100644
--- a/ctdb/server/ctdb_daemon.c
+++ b/ctdb/server/ctdb_daemon.c
@@ -691,6 +691,7 @@ static void daemon_request_call_from_client(struct ctdb_client *client,
if (header.flags & CTDB_REC_RO_REVOKE_COMPLETE) {
header.flags &= ~(CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY|CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_REVOKE_COMPLETE);
CTDB_INCREMENT_STAT(ctdb, total_ro_revokes);
+ CTDB_INCREMENT_DB_STAT(ctdb_db, db_ro_revokes);
if (ctdb_ltdb_store(ctdb_db, key, &header, data) != 0) {
ctdb_fatal(ctdb, "Failed to write header with cleared REVOKE flag");
}
diff --git a/ctdb/server/ctdb_ltdb_server.c b/ctdb/server/ctdb_ltdb_server.c
index 9a0132a362..e5437b99a2 100644
--- a/ctdb/server/ctdb_ltdb_server.c
+++ b/ctdb/server/ctdb_ltdb_server.c
@@ -1464,3 +1464,20 @@ int32_t ctdb_control_set_db_priority(struct ctdb_context *ctdb, TDB_DATA indata)
return 0;
}
+int32_t ctdb_control_get_db_statistics(struct ctdb_context *ctdb,
+ uint32_t db_id,
+ TDB_DATA *outdata)
+{
+ struct ctdb_db_context *ctdb_db;
+
+ ctdb_db = find_ctdb_db(ctdb, db_id);
+ if (!ctdb_db) {
+ DEBUG(DEBUG_ERR,("Unknown db_id 0x%x in get_db_statistics\n", db_id));
+ return -1;
+ }
+
+ outdata->dptr = (uint8_t *)&(ctdb_db->statistics);
+ outdata->dsize = sizeof(ctdb_db->statistics);
+
+ return 0;
+}
diff --git a/ctdb/tests/src/libctdb_test.c b/ctdb/tests/src/libctdb_test.c
index 73ba155a29..56c007e8e3 100644
--- a/ctdb/tests/src/libctdb_test.c
+++ b/ctdb/tests/src/libctdb_test.c
@@ -487,3 +487,20 @@ void ctdb_disconnect(struct ctdb_connection *ctdb)
free(ctdb);
}
+bool ctdb_getdbstat(struct ctdb_connection *ctdb,
+ uint32_t destnode,
+ uint32_t db_id,
+ struct ctdb_db_statistics **dbstatistics)
+{
+ if (!current_node_is_connected(ctdb)) {
+ return false;
+ }
+
+ *dbstatistics = malloc(sizeof(struct ctdb_db_statistics));
+ return true;
+}
+
+void ctdb_free_dbstat(struct ctdb_db_statistics *dbstatistics)
+{
+ free(dbstatistics);
+}
diff --git a/ctdb/tools/ctdb.c b/ctdb/tools/ctdb.c
index ceab2979ff..051a270d6e 100644
--- a/ctdb/tools/ctdb.c
+++ b/ctdb/tools/ctdb.c
@@ -566,6 +566,55 @@ static int control_stats(struct ctdb_context *ctdb, int argc, const char **argv)
/*
+ display remote ctdb db statistics
+ */
+static int control_dbstatistics(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ struct ctdb_db_statistics *dbstatistics;
+ struct ctdb_dbid_map *dbmap=NULL;
+ int i, ret;
+
+ if (argc < 1) {
+ usage();
+ }
+
+ ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &dbmap);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n", options.pnn));
+ return ret;
+ }
+ for(i=0;i<dbmap->num;i++){
+ const char *name;
+
+ ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, tmp_ctx, &name);
+ if(!strcmp(argv[0], name)){
+ talloc_free(discard_const(name));
+ break;
+ }
+ talloc_free(discard_const(name));
+ }
+ if (i == dbmap->num) {
+ DEBUG(DEBUG_ERR,("No database with name '%s' found\n", argv[0]));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ if (!ctdb_getdbstat(ctdb_connection, options.pnn, dbmap->dbs[i].dbid, &dbstatistics)) {
+ DEBUG(DEBUG_ERR,("Failed to read db statistics from node\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ printf("DB Statistics:\n");
+ printf("RO Delegations: %d\n", dbstatistics->db_ro_delegations);
+ printf("RO Revokes: %d\n", dbstatistics->db_ro_revokes);
+
+ ctdb_free_dbstat(dbstatistics);
+ return 0;
+}
+
+/*
display uptime of remote node
*/
static int control_uptime(struct ctdb_context *ctdb, int argc, const char **argv)
@@ -5434,6 +5483,7 @@ static const struct {
{ "checktcpport", control_chktcpport, false, true, "check if a service is bound to a specific tcp port or not", "<port>" },
{ "getdbseqnum", control_getdbseqnum, false, false, "get the sequence number off a database", "<dbid>" },
{ "nodestatus", control_nodestatus, true, false, "show and return node status" },
+ { "dbstatistics", control_dbstatistics, false, false, "show db statistics", "<db>" },
};
/*