diff options
author | Martin Schwenke <martin@meltin.net> | 2011-07-28 15:22:42 +1000 |
---|---|---|
committer | Ronnie Sahlberg <ronniesahlberg@gmail.com> | 2011-07-29 09:01:36 +1000 |
commit | 5ac67504caace31d9d529792ace03fbe133a0d59 (patch) | |
tree | fdde2507767d6f178409474c5607ace2ae34a788 | |
parent | ff1a81c872e1d3075984a68d73f3e1a2178186a1 (diff) | |
download | samba-5ac67504caace31d9d529792ace03fbe133a0d59.tar.gz samba-5ac67504caace31d9d529792ace03fbe133a0d59.tar.xz samba-5ac67504caace31d9d529792ace03fbe133a0d59.zip |
Tests: Initial test code for LCP2 IP allocation algorithm.
Move struct ctdb_public_ip_list to ctdb_private.h and put some
definitions for some functions from ctdb_takeover.c there. This
allows those functions to be called from unit tests.
Add ctdb_takeover_tests.c and the Makefile support to build it.
Signed-off-by: Martin Schwenke <martin@meltin.net>
(This used to be ctdb commit 9d34be0233edf3bc022345c0494c4b2a4d7f8480)
-rwxr-xr-x | ctdb/Makefile.in | 7 | ||||
-rw-r--r-- | ctdb/include/ctdb_private.h | 33 | ||||
-rw-r--r-- | ctdb/server/ctdb_takeover.c | 7 | ||||
-rw-r--r-- | ctdb/tests/src/ctdb_takeover_tests.c | 378 |
4 files changed, 418 insertions, 7 deletions
diff --git a/ctdb/Makefile.in b/ctdb/Makefile.in index aec64e1d9f2..5fa9e98c10d 100755 --- a/ctdb/Makefile.in +++ b/ctdb/Makefile.in @@ -70,6 +70,7 @@ TEST_BINS=tests/bin/ctdb_bench tests/bin/ctdb_fetch tests/bin/ctdb_fetch_one \ tests/bin/ctdb_fetch_lock_once tests/bin/ctdb_store \ tests/bin/ctdb_randrec tests/bin/ctdb_persistent \ tests/bin/ctdb_traverse tests/bin/rb_test tests/bin/ctdb_transaction \ + tests/bin/ctdb_takeover_tests @INFINIBAND_BINS@ BINS = bin/ctdb @CTDB_SCSI_IO@ bin/smnotify bin/ping_pong bin/ltdbtool @@ -190,6 +191,12 @@ tests/bin/ctdb_transaction: $(CTDB_CLIENT_OBJ) tests/src/ctdb_transaction.o @echo Linking $@ @$(CC) $(CFLAGS) -o $@ tests/src/ctdb_transaction.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS) +CTDB_TAKEOVER_OBJ = $(CTDB_SERVER_OBJ:server/ctdbd.o=) + +tests/bin/ctdb_takeover_tests: $(CTDB_TAKEOVER_OBJ) tests/src/ctdb_takeover_tests.o + @echo Linking $@ + @$(CC) $(CFLAGS) -o $@ tests/src/ctdb_takeover_tests.o $(CTDB_TAKEOVER_OBJ) $(LIB_FLAGS) + tests/bin/ibwrapper_test: $(CTDB_CLIENT_OBJ) ib/ibwrapper_test.o @echo Linking $@ @$(CC) $(CFLAGS) -o $@ ib/ibwrapper_test.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 8a24d3b676f..37f8a7344ad 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -1411,4 +1411,37 @@ int32_t ctdb_local_schedule_for_deletion(struct ctdb_db_context *ctdb_db, struct ctdb_ltdb_header *ctdb_header_from_record_handle(struct ctdb_record_handle *h); +/* For unit testing ctdb_transaction.c. */ +struct ctdb_public_ip_list { + struct ctdb_public_ip_list *next; + uint32_t pnn; + ctdb_sock_addr addr; +}; +uint32_t ip_distance(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2); +uint32_t ip_distance_2_sum(ctdb_sock_addr *ip, + struct ctdb_public_ip_list *ips, + int pnn); +uint32_t lcp2_imbalance(struct ctdb_public_ip_list * all_ips, int pnn); +void lcp2_init(struct ctdb_context * tmp_ctx, + struct ctdb_node_map * nodemap, + uint32_t mask, + struct ctdb_public_ip_list *all_ips, + uint32_t **lcp2_imbalances, + bool **newly_healthy); +void lcp2_allocate_unassigned(struct ctdb_context *ctdb, + struct ctdb_node_map *nodemap, + uint32_t mask, + struct ctdb_public_ip_list *all_ips, + uint32_t *lcp2_imbalances); +bool lcp2_failback(struct ctdb_context *ctdb, + struct ctdb_node_map *nodemap, + uint32_t mask, + struct ctdb_public_ip_list *all_ips, + uint32_t *lcp2_imbalances, + bool *newly_healthy); +void ctdb_takeover_run_core(struct ctdb_context *ctdb, + struct ctdb_node_map *nodemap, + struct ctdb_public_ip_list **all_ips_p); + + #endif diff --git a/ctdb/server/ctdb_takeover.c b/ctdb/server/ctdb_takeover.c index 74edd819b68..5512acc379b 100644 --- a/ctdb/server/ctdb_takeover.c +++ b/ctdb/server/ctdb_takeover.c @@ -1059,13 +1059,6 @@ int ctdb_set_single_public_ip(struct ctdb_context *ctdb, return 0; } -struct ctdb_public_ip_list { - struct ctdb_public_ip_list *next; - uint32_t pnn; - ctdb_sock_addr addr; -}; - - /* Given a physical node, return the number of public addresses that is currently assigned to this node. */ diff --git a/ctdb/tests/src/ctdb_takeover_tests.c b/ctdb/tests/src/ctdb_takeover_tests.c new file mode 100644 index 00000000000..5fd23320a3d --- /dev/null +++ b/ctdb/tests/src/ctdb_takeover_tests.c @@ -0,0 +1,378 @@ +/* + Tests for ctdb_takeover.c + + Copyright (C) Martin Schwenke 2011 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "../include/ctdb_private.h" + +/* + * Need these, since they're defined in ctdbd.c but we can't link + * that. + */ +int script_log_level; +bool fast_start; +void ctdb_load_nodes_file(struct ctdb_context *ctdb) {} + +/* Format of each line is "IP pnn" - the separator has to be at least + * 1 space (not a tab or whatever - a space!). + */ +static struct ctdb_public_ip_list * +read_ctdb_public_ip_list(TALLOC_CTX *ctx) +{ + char line[1024]; + ctdb_sock_addr addr; + char *t; + int pnn; + struct ctdb_public_ip_list *last = NULL; + + struct ctdb_public_ip_list *ret = NULL; + + while (fgets(line, sizeof(line), stdin) != NULL) { + + if ((t = strchr(line, ' ')) != NULL) { + /* Make line contain just the address */ + *t = '\0'; + /* Point to PNN or leading whitespace... */ + t++; + pnn = (int) strtol(t, (char **) NULL, 10); + } else { + /* Assume just an IP address, default to PNN -1 */ + if ((t = strchr(line, '\n')) != NULL) { + *t = '\0'; + } + pnn = -1; + } + + if (parse_ip(line, NULL, 0, &addr)) { + if (last == NULL) { + last = talloc(ctx, struct ctdb_public_ip_list); + } else { + last->next = talloc(ctx, struct ctdb_public_ip_list); + last = last->next; + } + last->next = NULL; + last->pnn = pnn; + memcpy(&(last->addr), &addr, sizeof(addr)); + if (ret == NULL) { + ret = last; + } + } else { + DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", line)); + } + } + + return ret; +} + +void print_ctdb_public_ip_list(struct ctdb_public_ip_list * ips) +{ + while (ips) { + printf("%s %d\n", ctdb_addr_to_str(&(ips->addr)), ips->pnn); + ips = ips->next; + } +} + +/* Read some IPs from stdin, 1 per line, parse them and then print + * them back out. */ +void ctdb_test_read_ctdb_public_ip_list(void) +{ + struct ctdb_public_ip_list *l; + + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + + l = read_ctdb_public_ip_list(tmp_ctx); + + print_ctdb_public_ip_list(l); + + talloc_free(tmp_ctx); +} + +/* Read 2 IPs from stdin, calculate the IP distance and print it. */ +void ctdb_test_ip_distance(void) +{ + struct ctdb_public_ip_list *l; + uint32_t distance; + + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + + l = read_ctdb_public_ip_list(tmp_ctx); + + if (l && l->next) { + distance = ip_distance(&(l->addr), &(l->next->addr)); + printf ("%lu\n", (unsigned long) distance); + } + + talloc_free(tmp_ctx); +} + +/* Read some IPs from stdin, calculate the sum of the squares of the + * IP distances between the 1st argument and those read that are on + * the given node. The given IP must one of the ones in the list. */ +void ctdb_test_ip_distance_2_sum(const char ip[], int pnn) +{ + struct ctdb_public_ip_list *l; + struct ctdb_public_ip_list *t; + ctdb_sock_addr addr; + uint32_t distance; + + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + + + l = read_ctdb_public_ip_list(tmp_ctx); + + if (l && parse_ip(ip, NULL, 0, &addr)) { + /* find the entry for the specified IP */ + for (t=l; t!=NULL; t=t->next) { + if (ctdb_same_ip(&(t->addr), &addr)) { + break; + } + } + + if (t == NULL) { + fprintf(stderr, "IP NOT PRESENT IN LIST"); + exit(1); + } + + distance = ip_distance_2_sum(&(t->addr), l, pnn); + printf ("%lu\n", (unsigned long) distance); + } else { + fprintf(stderr, "BAD INPUT"); + exit(1); + } + + talloc_free(tmp_ctx); +} + +/* Read some IPs from stdin, calculate the sume of the squares of the + * IP distances between the first and the rest, and print it. */ +void ctdb_test_lcp2_imbalance(int pnn) +{ + struct ctdb_public_ip_list *l; + uint32_t imbalance; + + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + + l = read_ctdb_public_ip_list(tmp_ctx); + + imbalance = lcp2_imbalance(l, pnn); + printf ("%lu\n", (unsigned long) imbalance); + + talloc_free(tmp_ctx); +} + +void ctdb_test_init(const char nodestates[], + struct ctdb_context **ctdb, + struct ctdb_public_ip_list **all_ips, + struct ctdb_node_map **nodemap) +{ + struct ctdb_public_ip_list *t; + struct ctdb_all_public_ips *available_public_ips; + int i, numips, numnodes; + + numnodes = strlen(nodestates); + + *ctdb = talloc_zero(NULL, struct ctdb_context); + + /* Fake things up... */ + (*ctdb)->num_nodes = numnodes; + + (*ctdb)->tunable.deterministic_public_ips = 0; + (*ctdb)->tunable.disable_ip_failover = 0; + (*ctdb)->tunable.no_ip_failback = 0; + + if (getenv("CTDB_LCP2")) { + if (strcmp(getenv("CTDB_LCP2"), "yes") == 0) { + (*ctdb)->tunable.lcp2_public_ip_assignment = 1; + } else { + (*ctdb)->tunable.lcp2_public_ip_assignment = 0; + } + } + + *nodemap = talloc_array(*ctdb, struct ctdb_node_map, numnodes); + (*nodemap)->num = numnodes; + + for (i=0; i < numnodes; i++) { + (*nodemap)->nodes[i].pnn = i; + (*nodemap)->nodes[i].flags = nodestates[i] - '0'; + /* *nodemap->nodes[i].sockaddr is uninitialised */ + } + + *all_ips = read_ctdb_public_ip_list(*ctdb); + numips = 0; + for (t = *all_ips; t != NULL; t = t->next) { + numips++; + } + + available_public_ips = talloc_array(*ctdb, struct ctdb_all_public_ips, numips); // FIXME: bogus size, overkill + available_public_ips->num = numips; + for (t = *all_ips, i=0; t != NULL && i < numips ; t = t->next, i++) { + available_public_ips->ips[i].pnn = t->pnn; + memcpy(&(available_public_ips->ips[i].addr), &(t->addr), sizeof(t->addr)); + } + + (*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill + + /* Setup both nodemap and ctdb->nodes. Mark all nodes as + * healthy - change this later. */ + for (i=0; i < numnodes; i++) { + uint32_t flags = nodestates[i] - '0' ? NODE_FLAGS_UNHEALTHY : 0; + (*nodemap)->nodes[i].pnn = i; + (*nodemap)->nodes[i].flags = flags; + /* nodemap->nodes[i].sockaddr is uninitialised */ + + (*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node); + (*ctdb)->nodes[i]->pnn = i; + (*ctdb)->nodes[i]->flags = flags; + (*ctdb)->nodes[i]->available_public_ips = available_public_ips; + (*ctdb)->nodes[i]->known_public_ips = available_public_ips; + } +} + +/* IP layout is read from stdin. */ +void ctdb_test_lcp2_allocate_unassigned(const char nodestates[]) +{ + struct ctdb_context *ctdb; + struct ctdb_public_ip_list *all_ips; + struct ctdb_node_map *nodemap; + + uint32_t *lcp2_imbalances; + bool *newly_healthy; + + ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap); + + lcp2_init(ctdb, nodemap, + NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED, + all_ips, &lcp2_imbalances, &newly_healthy); + + lcp2_allocate_unassigned(ctdb, nodemap, + NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED, + all_ips, lcp2_imbalances); + + print_ctdb_public_ip_list(all_ips); + + talloc_free(ctdb); +} + +/* IP layout is read from stdin. */ +void ctdb_test_lcp2_failback(const char nodestates[]) +{ + struct ctdb_context *ctdb; + struct ctdb_public_ip_list *all_ips; + struct ctdb_node_map *nodemap; + + uint32_t *lcp2_imbalances; + bool *newly_healthy; + + ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap); + + lcp2_init(ctdb, nodemap, + NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED, + all_ips, &lcp2_imbalances, &newly_healthy); + + lcp2_failback(ctdb, nodemap, + NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED, + all_ips, lcp2_imbalances, newly_healthy); + + print_ctdb_public_ip_list(all_ips); + + talloc_free(ctdb); +} + +/* IP layout is read from stdin. */ +void ctdb_test_lcp2_failback_loop(const char nodestates[]) +{ + struct ctdb_context *ctdb; + struct ctdb_public_ip_list *all_ips; + struct ctdb_node_map *nodemap; + + uint32_t *lcp2_imbalances; + bool *newly_healthy; + + ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap); + + lcp2_init(ctdb, nodemap, + NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED, + all_ips, &lcp2_imbalances, &newly_healthy); + +try_again: + if (lcp2_failback(ctdb, nodemap, + NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED, + all_ips, lcp2_imbalances, newly_healthy)) { + goto try_again; + } + + print_ctdb_public_ip_list(all_ips); + + talloc_free(ctdb); +} + +/* IP layout is read from stdin. */ +void ctdb_test_ctdb_takeover_run_core(const char nodestates[]) +{ + struct ctdb_context *ctdb; + struct ctdb_public_ip_list *all_ips; + struct ctdb_node_map *nodemap; + + ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap); + + ctdb_takeover_run_core(ctdb, nodemap, &all_ips); + + print_ctdb_public_ip_list(all_ips); + + talloc_free(ctdb); +} + +void usage(void) +{ + fprintf(stderr, "usage: ctdb_takeover_tests <op>\n"); + exit(1); +} + +int main(int argc, const char *argv[]) +{ + LogLevel = DEBUG_DEBUG; + if (getenv("CTDB_TEST_LOGLEVEL")) { + LogLevel = atoi(getenv("CTDB_TEST_LOGLEVEL")); + } + + if (argc < 2) { + usage(); + } + + if (strcmp(argv[1], "ip_list") == 0) { + ctdb_test_read_ctdb_public_ip_list(); + } else if (strcmp(argv[1], "ip_distance") == 0) { + ctdb_test_ip_distance(); + } else if (argc == 4 && strcmp(argv[1], "ip_distance_2_sum") == 0) { + ctdb_test_ip_distance_2_sum(argv[2], atoi(argv[3])); + } else if (argc >= 3 && strcmp(argv[1], "lcp2_imbalance") == 0) { + ctdb_test_lcp2_imbalance(atoi(argv[2])); + } else if (argc == 3 && strcmp(argv[1], "lcp2_allocate_unassigned") == 0) { + ctdb_test_lcp2_allocate_unassigned(argv[2]); + } else if (argc == 3 && strcmp(argv[1], "lcp2_failback") == 0) { + ctdb_test_lcp2_failback(argv[2]); + } else if (argc == 3 && strcmp(argv[1], "lcp2_failback_loop") == 0) { + ctdb_test_lcp2_failback_loop(argv[2]); + } else if (argc == 3 && strcmp(argv[1], "ctdb_takeover_run_core") == 0) { + ctdb_test_ctdb_takeover_run_core(argv[2]); + } else { + usage(); + } + + return 0; +} |