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:
parent
7afabb1285
commit
5447864e5d
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user