1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-22 22:04:08 +03:00

ctdb-recovery: Replace use of ctdb_dbid_map with local db_list

This will be used to build a merged list of databases from all nodes,
allowing the recovery helper to create missing databases.

It would be possible to also include the db_name field in this
structure but that would cause a lot of churn.  This field is used
locally in the recovery of each database so can continue to live in
the relevant state structure(s).

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14294

Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
This commit is contained in:
Martin Schwenke 2020-02-21 12:24:39 +11:00 committed by Martin Schwenke
parent 7e5a8a4884
commit 4c0b9c3605

View File

@ -27,6 +27,7 @@
#include <libgen.h>
#include "lib/tdb_wrap/tdb_wrap.h"
#include "lib/util/dlinklist.h"
#include "lib/util/sys_rw.h"
#include "lib/util/time.h"
#include "lib/util/tevent_unix.h"
@ -169,6 +170,130 @@ static void node_list_ban_credits(struct node_list *nlist, uint32_t pnn)
}
}
/*
* Database list functions
*
* Simple, naive implementation that could be updated to a db_hash or similar
*/
struct db {
struct db *prev, *next;
uint32_t db_id;
uint32_t db_flags;
uint32_t *pnn_list;
unsigned int num_nodes;
};
struct db_list {
unsigned int num_dbs;
struct db *db;
unsigned int num_nodes;
};
static struct db_list *db_list_init(TALLOC_CTX *mem_ctx, unsigned int num_nodes)
{
struct db_list *l;
l = talloc_zero(mem_ctx, struct db_list);
l->num_nodes = num_nodes;
return l;
}
static struct db *db_list_find(struct db_list *dblist, uint32_t db_id)
{
struct db *db;
if (dblist == NULL) {
return NULL;
}
db = dblist->db;
while (db != NULL && db->db_id != db_id) {
db = db->next;
}
return db;
}
static int db_list_add(struct db_list *dblist,
uint32_t db_id,
uint32_t db_flags,
uint32_t node)
{
struct db *db = NULL;
if (dblist == NULL) {
return EINVAL;
}
db = talloc_zero(dblist, struct db);
if (db == NULL) {
return ENOMEM;
}
db->db_id = db_id;
db->db_flags = db_flags;
db->pnn_list = talloc_zero_array(db, uint32_t, dblist->num_nodes);
if (db->pnn_list == NULL) {
talloc_free(db);
return ENOMEM;
}
db->pnn_list[0] = node;
db->num_nodes = 1;
DLIST_ADD_END(dblist->db, db);
dblist->num_dbs++;
return 0;
}
static int db_list_check_and_add(struct db_list *dblist,
uint32_t db_id,
uint32_t db_flags,
uint32_t node)
{
struct db *db = NULL;
int ret;
/*
* These flags are masked out because they are only set on a
* node when a client attaches to that node, so they might not
* be set yet. They can't be passed as part of the attch, so
* they're no use here.
*/
db_flags &= ~(CTDB_DB_FLAGS_READONLY | CTDB_DB_FLAGS_STICKY);
if (dblist == NULL) {
return EINVAL;
}
db = db_list_find(dblist, db_id);
if (db == NULL) {
ret = db_list_add(dblist, db_id, db_flags, node);
return ret;
}
if (db->db_flags != db_flags) {
D_ERR("Incompatible database flags for 0x%"PRIx32" "
"(0x%"PRIx32" != 0x%"PRIx32")\n",
db_id,
db_flags,
db->db_flags);
return EINVAL;
}
if (db->num_nodes >= dblist->num_nodes) {
return EINVAL;
}
db->pnn_list[db->num_nodes] = node;
db->num_nodes++;
return 0;
}
/*
* Recovery database functions
*/
@ -2014,7 +2139,7 @@ static bool recover_db_recv(struct tevent_req *req)
struct db_recovery_state {
struct tevent_context *ev;
struct ctdb_dbid_map *dbmap;
struct db_list *dblist;
unsigned int num_replies;
unsigned int num_failed;
};
@ -2022,7 +2147,7 @@ struct db_recovery_state {
struct db_recovery_one_state {
struct tevent_req *req;
struct ctdb_client_context *client;
struct ctdb_dbid_map *dbmap;
struct db_list *dblist;
struct ctdb_tunable_list *tun_list;
struct node_list *nlist;
uint32_t generation;
@ -2036,14 +2161,14 @@ static void db_recovery_one_done(struct tevent_req *subreq);
static struct tevent_req *db_recovery_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ctdb_client_context *client,
struct ctdb_dbid_map *dbmap,
struct db_list *dblist,
struct ctdb_tunable_list *tun_list,
struct node_list *nlist,
uint32_t generation)
{
struct tevent_req *req, *subreq;
struct db_recovery_state *state;
unsigned int i;
struct db *db;
req = tevent_req_create(mem_ctx, &state, struct db_recovery_state);
if (req == NULL) {
@ -2051,16 +2176,16 @@ static struct tevent_req *db_recovery_send(TALLOC_CTX *mem_ctx,
}
state->ev = ev;
state->dbmap = dbmap;
state->dblist = dblist;
state->num_replies = 0;
state->num_failed = 0;
if (dbmap->num == 0) {
if (dblist->num_dbs == 0) {
tevent_req_done(req);
return tevent_req_post(req, ev);
}
for (i=0; i<dbmap->num; i++) {
for (db = dblist->db; db != NULL; db = db->next) {
struct db_recovery_one_state *substate;
substate = talloc_zero(state, struct db_recovery_one_state);
@ -2070,12 +2195,12 @@ static struct tevent_req *db_recovery_send(TALLOC_CTX *mem_ctx,
substate->req = req;
substate->client = client;
substate->dbmap = dbmap;
substate->dblist = dblist;
substate->tun_list = tun_list;
substate->nlist = nlist;
substate->generation = generation;
substate->db_id = dbmap->dbs[i].db_id;
substate->db_flags = dbmap->dbs[i].flags;
substate->db_id = db->db_id;
substate->db_flags = db->db_flags;
subreq = recover_db_send(state,
ev,
@ -2138,7 +2263,7 @@ failed:
done:
state->num_replies += 1;
if (state->num_replies == state->dbmap->num) {
if (state->num_replies == state->dblist->num_dbs) {
tevent_req_done(req);
}
}
@ -2387,7 +2512,7 @@ struct recovery_state {
struct node_list *nlist;
struct ctdb_tunable_list *tun_list;
struct ctdb_vnn_map *vnnmap;
struct ctdb_dbid_map *dbmap;
struct db_list *dblist;
};
static void recovery_tunables_done(struct tevent_req *subreq);
@ -2709,6 +2834,8 @@ static void recovery_dbmap_done(struct tevent_req *subreq)
req, struct recovery_state);
struct ctdb_reply_control *reply;
struct ctdb_req_control request;
struct ctdb_dbid_map *dbmap = NULL;
unsigned int j;
int ret;
bool status;
@ -2721,13 +2848,32 @@ static void recovery_dbmap_done(struct tevent_req *subreq)
return;
}
ret = ctdb_reply_control_get_dbmap(reply, state, &state->dbmap);
state->dblist = db_list_init(state, state->nlist->count);
if (tevent_req_nomem(state->dblist, req)) {
D_ERR("memory allocation error\n");
return;
}
ret = ctdb_reply_control_get_dbmap(reply, state, &dbmap);
if (ret != 0) {
D_ERR("control GET_DBMAP failed, ret=%d\n", ret);
tevent_req_error(req, ret);
return;
}
for (j = 0; j < dbmap->num; j++) {
ret = db_list_check_and_add(state->dblist,
dbmap->dbs[j].db_id,
dbmap->dbs[j].flags,
state->destnode);
if (ret != 0) {
D_ERR("failed to add database list entry, ret=%d\n",
ret);
tevent_req_error(req, ret);
return;
}
}
ctdb_req_control_set_recmode(&request, CTDB_RECOVERY_ACTIVE);
subreq = ctdb_client_control_multi_send(state,
state->ev,
@ -2898,7 +3044,7 @@ static void recovery_vnnmap_update_done(struct tevent_req *subreq)
subreq = db_recovery_send(state,
state->ev,
state->client,
state->dbmap,
state->dblist,
state->tun_list,
state->nlist,
state->vnnmap->generation);
@ -2921,7 +3067,7 @@ static void recovery_db_recovery_done(struct tevent_req *subreq)
status = db_recovery_recv(subreq, &count);
TALLOC_FREE(subreq);
D_ERR("%d of %d databases recovered\n", count, state->dbmap->num);
D_ERR("%d of %d databases recovered\n", count, state->dblist->num_dbs);
if (! status) {
subreq = ban_node_send(state,