summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmitay Isaacs <amitay@gmail.com>2014-08-05 14:16:29 +1000
committerAmitay Isaacs <amitay@samba.org>2015-10-07 14:53:26 +0200
commit5447864e5d31d433f9a54924f3bb01f1384620fd (patch)
treeb940be008c1d084f0a83410ed4fa7c5781c037b4
parent7afabb1285f6778b5b2862e178315b03f54eb8ef (diff)
downloadsamba-5447864e5d31d433f9a54924f3bb01f1384620fd.tar.gz
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>
-rw-r--r--ctdb/include/ctdb_private.h11
-rw-r--r--ctdb/include/ctdb_protocol.h2
-rw-r--r--ctdb/server/ctdb_control.c9
-rw-r--r--ctdb/server/ctdb_freeze.c182
4 files changed, 204 insertions, 0 deletions
diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h
index 83b8bd2b84e..b6f7263b8b7 100644
--- a/ctdb/include/ctdb_private.h
+++ b/ctdb/include/ctdb_private.h
@@ -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);
diff --git a/ctdb/include/ctdb_protocol.h b/ctdb/include/ctdb_protocol.h
index d9cad7c6f18..6169c8fe781 100644
--- a/ctdb/include/ctdb_protocol.h
+++ b/ctdb/include/ctdb_protocol.h
@@ -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,
};
/*
diff --git a/ctdb/server/ctdb_control.c b/ctdb/server/ctdb_control.c
index 7b26ff96983..e7c76204104 100644
--- a/ctdb/server/ctdb_control.c
+++ b/ctdb/server/ctdb_control.c
@@ -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;
diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c
index 6b6a712e91f..5dc1b7c5826 100644
--- a/ctdb/server/ctdb_freeze.c
+++ b/ctdb/server/ctdb_freeze.c
@@ -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) {