diff --git a/ctdb/common/ctdb_client.c b/ctdb/common/ctdb_client.c index 5b30123012e..5b6031852d3 100644 --- a/ctdb/common/ctdb_client.c +++ b/ctdb/common/ctdb_client.c @@ -843,7 +843,7 @@ int ctdb_ctrl_setrecmode(struct ctdb_context *ctdb, uint32_t destnode, uint32_t /* get a list of databases off a remote node */ -int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_dbid_map *dbmap) +int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_dbid_map *dbmap) { int ret; TDB_DATA data, outdata; @@ -852,18 +852,14 @@ int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb ZERO_STRUCT(data); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DBMAP, data, - ctdb, &outdata, &res); + mem_ctx, &outdata, &res); if (ret != 0 || res != 0) { DEBUG(0,(__location__ " ctdb_control for getvnnmap failed\n")); return -1; } dbmap->num = ((uint32_t *)outdata.dptr)[0]; - if (dbmap->dbids) { - talloc_free(dbmap->dbids); - dbmap->dbids=NULL; - } - dbmap->dbids=talloc_array(dbmap, uint32_t, dbmap->num); + dbmap->dbids=talloc_array(mem_ctx, uint32_t, dbmap->num); if (!dbmap->dbids) { DEBUG(0,(__location__ " failed to talloc dbmap\n")); return -1; @@ -911,13 +907,13 @@ int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb, uint32_t destnode, /* set vnn map on a node */ -int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_vnn_map *vnnmap) +int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_vnn_map *vnnmap) { int ret; TDB_DATA *data, outdata; int32_t i, res; - data = talloc_zero(ctdb, TDB_DATA); + data = talloc_zero(mem_ctx, TDB_DATA); data->dsize = (vnnmap->size+2)*sizeof(uint32_t); data->dptr = (unsigned char *)talloc_array(data, uint32_t, vnnmap->size+2); @@ -929,7 +925,7 @@ int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctd ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SETVNNMAP, *data, - ctdb, &outdata, &res); + mem_ctx, &outdata, &res); if (ret != 0 || res != 0) { DEBUG(0,(__location__ " ctdb_control for setvnnmap failed\n")); return -1; @@ -942,15 +938,18 @@ int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctd /* get all keys and records for a specific database */ -int ctdb_ctrl_pulldb(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, struct ctdb_key_list *keys) +int ctdb_ctrl_pulldb(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, uint32_t lmaster, TALLOC_CTX *mem_ctx, struct ctdb_key_list *keys) { int i, ret; TDB_DATA indata, outdata; int32_t res; unsigned char *ptr; - indata.dsize = sizeof(uint32_t); - indata.dptr = (unsigned char *)&dbid; + indata.dsize = 2*sizeof(uint32_t); + indata.dptr = (unsigned char *)talloc_array(mem_ctx, uint32_t, 2); + + ((uint32_t *)(&indata.dptr[0]))[0] = dbid; + ((uint32_t *)(&indata.dptr[0]))[1] = lmaster; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_PULL_DB, indata, @@ -1005,14 +1004,17 @@ int ctdb_ctrl_pulldb(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid /* copy a tdb from one node to another node */ -int ctdb_ctrl_copydb(struct ctdb_context *ctdb, uint32_t sourcenode, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx) +int ctdb_ctrl_copydb(struct ctdb_context *ctdb, uint32_t sourcenode, uint32_t destnode, uint32_t dbid, uint32_t lmaster, TALLOC_CTX *mem_ctx) { int ret; TDB_DATA indata, outdata; int32_t res; - indata.dsize = sizeof(uint32_t); - indata.dptr = (unsigned char *)&dbid; + indata.dsize = 2*sizeof(uint32_t); + indata.dptr = (unsigned char *)talloc_array(mem_ctx, uint32_t, 2); + + ((uint32_t *)(&indata.dptr[0]))[0] = dbid; + ((uint32_t *)(&indata.dptr[0]))[1] = lmaster; ret = ctdb_control(ctdb, sourcenode, 0, CTDB_CONTROL_PULL_DB, indata, diff --git a/ctdb/common/ctdb_control.c b/ctdb/common/ctdb_control.c index 19938652421..b605e492b7a 100644 --- a/ctdb/common/ctdb_control.c +++ b/ctdb/common/ctdb_control.c @@ -75,6 +75,7 @@ static int traverse_setdmaster(struct tdb_context *tdb, TDB_DATA key, TDB_DATA d struct getkeys_params { struct ctdb_db_context *ctdb_db; TDB_DATA *outdata; + uint32_t lmaster; }; static int traverse_getkeys(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *p) @@ -84,6 +85,17 @@ static int traverse_getkeys(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data struct ctdb_db_context *ctdb_db = talloc_get_type(params->ctdb_db, struct ctdb_db_context); unsigned char *ptr; int len; + uint32_t lmaster; + + lmaster = ctdb_lmaster(ctdb_db->ctdb, &key); + + /* only include this record if the lmaster matches or if + the wildcard lmaster (-1) was specified. + */ + if((lmaster!=CTDB_LMASTER_ANY) + && (lmaster!=params->lmaster) ){ + return 0; + } len=outdata->dsize; len+=4; /*lmaster*/ @@ -102,7 +114,7 @@ static int traverse_getkeys(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data /* number of records is stored as the second 4 bytes */ ((uint32_t *)(&outdata->dptr[0]))[1]++; - *((uint32_t *)ptr)=ctdb_lmaster(ctdb_db->ctdb, &key); + *((uint32_t *)ptr)=lmaster; ptr+=4; *((uint32_t *)ptr)=key.dsize; @@ -254,17 +266,19 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, } case CTDB_CONTROL_PULL_DB: { - uint32_t dbid; + uint32_t dbid, lmaster; struct ctdb_db_context *ctdb_db; struct getkeys_params params; - dbid = *((uint32_t *)(&indata.dptr[0])); + dbid = ((uint32_t *)(&indata.dptr[0]))[0]; ctdb_db = find_ctdb_db(ctdb, dbid); if (!ctdb_db) { DEBUG(0,(__location__ " Unknown db\n")); return -1; } + lmaster = ((uint32_t *)(&indata.dptr[0]))[1]; + outdata->dsize = 2* sizeof(uint32_t); outdata->dptr = (unsigned char *)talloc_array(outdata, uint32_t, 2); ((uint32_t *)(&outdata->dptr[0]))[0]=dbid; @@ -272,6 +286,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, params.ctdb_db = ctdb_db; params.outdata = outdata; + params.lmaster = lmaster; tdb_traverse_read(ctdb_db->ltdb->tdb, traverse_getkeys, ¶ms); @@ -324,7 +339,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, unsigned char *ptr; int i, ret; TDB_DATA key, data; - struct ctdb_ltdb_header header; + struct ctdb_ltdb_header *hdr, header; outdata->dsize = 0; outdata->dptr = NULL; @@ -350,7 +365,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, ptr+=(key.dsize+CTDB_DS_ALIGNMENT-1)& ~(CTDB_DS_ALIGNMENT-1); /* header */ - memcpy(&header, ptr, sizeof(struct ctdb_ltdb_header)); + hdr = (struct ctdb_ltdb_header *)ptr; ptr+=(sizeof(struct ctdb_ltdb_header)+CTDB_DS_ALIGNMENT-1)& ~(CTDB_DS_ALIGNMENT-1); /* data */ @@ -364,12 +379,20 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, DEBUG(0, (__location__ "Unable to lock db\n")); return -1; } - ret = ctdb_ltdb_store(ctdb_db, key, &header, data); + ret = ctdb_ltdb_fetch(ctdb_db, key, &header, outdata, NULL); if (ret != 0) { - DEBUG(0, (__location__ "Unable to store record\n")); + DEBUG(0, (__location__ "Unable to fetch record\n")); ctdb_ltdb_unlock(ctdb_db, key); return -1; } + if (header.rsn > hdr->rsn) { + ret = ctdb_ltdb_store(ctdb_db, key, hdr, data); + if (ret != 0) { + DEBUG(0, (__location__ "Unable to store record\n")); + ctdb_ltdb_unlock(ctdb_db, key); + return -1; + } + } ctdb_ltdb_unlock(ctdb_db, key); } diff --git a/ctdb/include/ctdb.h b/ctdb/include/ctdb.h index cfb01a301bd..47b7c9f3b16 100644 --- a/ctdb/include/ctdb.h +++ b/ctdb/include/ctdb.h @@ -217,7 +217,7 @@ int ctdb_ctrl_status(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_s struct ctdb_vnn_map; int ctdb_ctrl_getvnnmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_vnn_map *vnnmap); -int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_vnn_map *vnnmap); +int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_vnn_map *vnnmap); /* table that contains a list of all dbids on a node */ @@ -225,7 +225,7 @@ struct ctdb_dbid_map { uint32_t num; uint32_t *dbids; }; -int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_dbid_map *dbmap); +int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_dbid_map *dbmap); /* table that contains a list of all nodes a ctdb knows about and their @@ -250,8 +250,8 @@ struct ctdb_key_list { uint32_t *lmasters; TDB_DATA *data; }; -int ctdb_ctrl_pulldb(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, struct ctdb_key_list *keys); -int ctdb_ctrl_copydb(struct ctdb_context *ctdb, uint32_t sourcenode, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx); +int ctdb_ctrl_pulldb(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, uint32_t lmaster, TALLOC_CTX *mem_ctx, struct ctdb_key_list *keys); +int ctdb_ctrl_copydb(struct ctdb_context *ctdb, uint32_t sourcenode, uint32_t destnode, uint32_t dbid, uint32_t lmaster, TALLOC_CTX *mem_ctx); int ctdb_ctrl_getdbpath(struct ctdb_context *ctdb, uint32_t dbid, TALLOC_CTX *mem_ctx, const char **path); diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index e6a0fb40534..e9a9e3e689d 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -263,6 +263,8 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS, enum call_state {CTDB_CALL_WAIT, CTDB_CALL_DONE, CTDB_CALL_ERROR}; +#define CTDB_LMASTER_ANY 0xffffffff + /* state of a in-progress ctdb call */ diff --git a/ctdb/tools/ctdb_control.c b/ctdb/tools/ctdb_control.c index b96b7e1132c..29b9984ce5f 100644 --- a/ctdb/tools/ctdb_control.c +++ b/ctdb/tools/ctdb_control.c @@ -49,6 +49,7 @@ static void usage(void) printf(" cleardb deletes all records in a db\n"); printf(" getrecmode get recovery mode\n"); printf(" setrecmode set recovery mode\n"); + printf(" recover recover the cluster\n"); exit(1); } @@ -227,6 +228,190 @@ static int control_status_reset(struct ctdb_context *ctdb, int argc, const char return 0; } + +/* + perform a samba3 style recovery + */ +static int control_recover(struct ctdb_context *ctdb, int argc, const char **argv) +{ + uint32_t vnn, num_nodes, generation, dmaster; + struct ctdb_vnn_map vnnmap; + struct ctdb_node_map nodemap; + int i, j, ret; + struct ctdb_dbid_map dbmap; + + vnn = ctdb_get_vnn(ctdb); + printf("recover\n"); + printf("this vnn:%d\n",vnn); + + /* 1: find a list of all nodes */ + printf("\n1: fetching list of nodes\n"); + ret = ctdb_ctrl_getnodemap(ctdb, vnn, ctdb, &nodemap); + if (ret != 0) { + printf("Unable to get nodemap from node %u\n", vnn); + return ret; + } + + /* 2: count the active nodes */ + printf("\n2: count number of active nodes\n"); + num_nodes = 0; + for (i=0; inum); - for(i=0;inum;i++){ + printf("Number of databases:%d\n", dbmap.num); + for(i=0;idbids[i], dbmap, &path); - printf("dbid:0x%08x path:%s\n", dbmap->dbids[i], path); + ctdb_ctrl_getdbpath(ctdb, dbmap.dbids[i], ctdb, &path); + printf("dbid:0x%08x path:%s\n", dbmap.dbids[i], path); } - talloc_free(dbmap); + return 0; } @@ -464,7 +647,7 @@ static int control_setvnnmap(struct ctdb_context *ctdb, int argc, const char **a vnnmap->map[i] = strtoul(argv[3+i], NULL, 0); } - ret = ctdb_ctrl_setvnnmap(ctdb, vnn, vnnmap); + ret = ctdb_ctrl_setvnnmap(ctdb, vnn, ctdb, vnnmap); if (ret != 0) { printf("Unable to set vnnmap for node %u\n", vnn); return ret; @@ -695,6 +878,8 @@ int main(int argc, const char *argv[]) ret = control_debug(ctdb, extra_argc-1, extra_argv+1); } else if (strcmp(control, "debuglevel") == 0) { ret = control_debuglevel(ctdb, extra_argc-1, extra_argv+1); + } else if (strcmp(control, "recover") == 0) { + ret = control_recover(ctdb, extra_argc-1, extra_argv+1); } else { printf("Unknown control '%s'\n", control); exit(1);