1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

ctdb-daemon: Add controls to freeze/thaw a single database

Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
This commit is contained in:
Amitay Isaacs 2014-08-05 14:16:29 +10:00 committed by Amitay Isaacs
parent 7afabb1285
commit 5447864e5d
4 changed files with 204 additions and 0 deletions

View File

@ -585,6 +585,11 @@ struct ctdb_db_context {
int lock_num_current;
struct ctdb_call_state *pending_calls;
enum ctdb_freeze_mode freeze_mode;
struct ctdb_db_freeze_handle *freeze_handle;
bool freeze_transaction_started;
uint32_t freeze_transaction_id;
};
@ -994,9 +999,15 @@ int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb,
void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_control *c,
TDB_DATA *outdata, int32_t status, const char *errormsg);
int32_t ctdb_control_db_freeze(struct ctdb_context *ctdb,
struct ctdb_req_control *c,
uint32_t db_id, bool *async_reply);
int32_t ctdb_control_db_thaw(struct ctdb_context *ctdb, uint32_t db_id);
int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply);
int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority,
bool check_recmode);
bool ctdb_db_frozen(struct ctdb_db_context *ctdb_db);
bool ctdb_db_prio_frozen(struct ctdb_context *ctdb, uint32_t priority);
bool ctdb_db_all_frozen(struct ctdb_context *ctdb);

View File

@ -415,6 +415,8 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0,
CTDB_CONTROL_GET_RUNSTATE = 138,
CTDB_CONTROL_DB_DETACH = 139,
CTDB_CONTROL_GET_NODES_FILE = 140,
CTDB_CONTROL_DB_FREEZE = 141,
CTDB_CONTROL_DB_THAW = 142,
};
/*

View File

@ -683,6 +683,15 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
case CTDB_CONTROL_DB_DETACH:
return ctdb_control_db_detach(ctdb, indata, client_id);
case CTDB_CONTROL_DB_FREEZE:
CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
return ctdb_control_db_freeze(ctdb, c, *(uint32_t *)indata.dptr,
async_reply);
case CTDB_CONTROL_DB_THAW:
CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
return ctdb_control_db_thaw(ctdb, *(uint32_t *)indata.dptr);
default:
DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
return -1;

View File

@ -101,6 +101,179 @@ static int db_transaction_commit_handler(struct ctdb_db_context *ctdb_db,
}
/* a list of control requests waiting for db freeze */
struct ctdb_db_freeze_waiter {
struct ctdb_db_freeze_waiter *next, *prev;
struct ctdb_context *ctdb;
void *private_data;
int32_t status;
};
/* a handle to a db freeze lock child process */
struct ctdb_db_freeze_handle {
struct ctdb_db_context *ctdb_db;
struct lock_request *lreq;
struct ctdb_db_freeze_waiter *waiters;
};
/**
* Called when freeing database freeze handle
*/
static int ctdb_db_freeze_handle_destructor(struct ctdb_db_freeze_handle *h)
{
struct ctdb_db_context *ctdb_db = h->ctdb_db;
DEBUG(DEBUG_ERR, ("Release freeze handle for db %s\n",
ctdb_db->db_name));
/* Cancel any pending transactions */
if (ctdb_db->freeze_transaction_started) {
db_transaction_cancel_handler(ctdb_db, NULL);
ctdb_db->freeze_transaction_started = false;
}
ctdb_db->freeze_mode = CTDB_FREEZE_NONE;
ctdb_db->freeze_handle = NULL;
talloc_free(h->lreq);
return 0;
}
/**
* Called when a database is frozen
*/
static void ctdb_db_freeze_handler(void *private_data, bool locked)
{
struct ctdb_db_freeze_handle *h = talloc_get_type_abort(
private_data, struct ctdb_db_freeze_handle);
struct ctdb_db_freeze_waiter *w;
if (h->ctdb_db->freeze_mode == CTDB_FREEZE_FROZEN) {
DEBUG(DEBUG_ERR, ("Freeze db child died - unfreezing\n"));
h->ctdb_db->freeze_mode = CTDB_FREEZE_NONE;
talloc_free(h);
return;
}
if (!locked) {
DEBUG(DEBUG_ERR, ("Failed to get db lock for %s\n",
h->ctdb_db->db_name));
h->ctdb_db->freeze_mode = CTDB_FREEZE_NONE;
talloc_free(h);
return;
}
h->ctdb_db->freeze_mode = CTDB_FREEZE_FROZEN;
/* notify the waiters */
while ((w = h->waiters) != NULL) {
w->status = 0;
DLIST_REMOVE(h->waiters, w);
talloc_free(w);
}
}
/**
* Start freeze process for a database
*/
static void ctdb_start_db_freeze(struct ctdb_db_context *ctdb_db)
{
struct ctdb_db_freeze_handle *h;
if (ctdb_db->freeze_mode == CTDB_FREEZE_FROZEN) {
return;
}
if (ctdb_db->freeze_handle != NULL) {
return;
}
DEBUG(DEBUG_ERR, ("Freeze db: %s\n", ctdb_db->db_name));
ctdb_stop_vacuuming(ctdb_db->ctdb);
h = talloc_zero(ctdb_db, struct ctdb_db_freeze_handle);
CTDB_NO_MEMORY_FATAL(ctdb_db->ctdb, h);
h->ctdb_db = ctdb_db;
h->lreq = ctdb_lock_db(h, ctdb_db, false, ctdb_db_freeze_handler, h);
CTDB_NO_MEMORY_FATAL(ctdb_db->ctdb, h->lreq);
talloc_set_destructor(h, ctdb_db_freeze_handle_destructor);
ctdb_db->freeze_handle = h;
ctdb_db->freeze_mode = CTDB_FREEZE_PENDING;
}
/**
* Reply to a waiter for db freeze
*/
static int ctdb_db_freeze_waiter_destructor(struct ctdb_db_freeze_waiter *w)
{
/* 'c' pointer is talloc_memdup(), so cannot use talloc_get_type */
struct ctdb_req_control *c =
(struct ctdb_req_control *)w->private_data;
ctdb_request_control_reply(w->ctdb, c, NULL, w->status, NULL);
return 0;
}
/**
* freeze a database
*/
int32_t ctdb_control_db_freeze(struct ctdb_context *ctdb,
struct ctdb_req_control *c,
uint32_t db_id,
bool *async_reply)
{
struct ctdb_db_context *ctdb_db;
struct ctdb_db_freeze_waiter *w;
ctdb_db = find_ctdb_db(ctdb, db_id);
if (ctdb_db == NULL) {
DEBUG(DEBUG_ERR, ("Freeze db for unknown dbid 0x%08x\n", db_id));
return -1;
}
if (ctdb_db->freeze_mode == CTDB_FREEZE_FROZEN) {
DEBUG(DEBUG_ERR, ("Freeze db: %s frozen\n", ctdb_db->db_name));
return 0;
}
ctdb_start_db_freeze(ctdb_db);
/* add ourselves to the list of waiters */
w = talloc(ctdb_db->freeze_handle, struct ctdb_db_freeze_waiter);
CTDB_NO_MEMORY(ctdb, w);
w->ctdb = ctdb;
w->private_data = talloc_steal(w, c);
w->status = -1;
talloc_set_destructor(w, ctdb_db_freeze_waiter_destructor);
DLIST_ADD(ctdb_db->freeze_handle->waiters, w);
*async_reply = true;
return 0;
}
/**
* Thaw a database
*/
int32_t ctdb_control_db_thaw(struct ctdb_context *ctdb, uint32_t db_id)
{
struct ctdb_db_context *ctdb_db;
ctdb_db = find_ctdb_db(ctdb, db_id);
if (ctdb_db == NULL) {
DEBUG(DEBUG_ERR, ("Thaw db for unknown dbid 0x%08x\n", db_id));
return -1;
}
DEBUG(DEBUG_ERR, ("Thaw db: %s\n", ctdb_db->db_name));
TALLOC_FREE(ctdb_db->freeze_handle);
ctdb_call_resend_db(ctdb_db);
return 0;
}
/*
a list of control requests waiting for a freeze lock child to get
the database locks
@ -487,6 +660,15 @@ int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata)
return 0;
}
bool ctdb_db_frozen(struct ctdb_db_context *ctdb_db)
{
if (ctdb_db->freeze_mode != CTDB_FREEZE_FROZEN) {
return false;
}
return true;
}
bool ctdb_db_prio_frozen(struct ctdb_context *ctdb, uint32_t priority)
{
if (priority == 0) {