4 Copyright (C) Andrew Tridgell 2007
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/network.h"
22 #include "system/filesys.h"
23 #include "system/wait.h"
24 #include "../include/ctdb_private.h"
25 #include "lib/util/dlinklist.h"
26 #include "lib/tdb_wrap/tdb_wrap.h"
27 #include "../common/rb_tree.h"
31 * Cancel a transaction on database
33 static int db_transaction_cancel_handler(struct ctdb_db_context *ctdb_db,
38 tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
39 ret = tdb_transaction_cancel(ctdb_db->ltdb->tdb);
41 DEBUG(DEBUG_ERR, ("Failed to cancel transaction for db %s\n",
44 tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
49 * Start a transaction on database
51 static int db_transaction_start_handler(struct ctdb_db_context *ctdb_db,
54 bool freeze_transaction_started = *(bool *)private_data;
57 tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
58 if (freeze_transaction_started) {
59 ret = tdb_transaction_cancel(ctdb_db->ltdb->tdb);
62 ("Failed to cancel transaction for db %s\n",
66 ret = tdb_transaction_start(ctdb_db->ltdb->tdb);
67 tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
69 DEBUG(DEBUG_ERR, ("Failed to start transaction for db %s\n",
77 * Commit a transaction on database
79 static int db_transaction_commit_handler(struct ctdb_db_context *ctdb_db,
82 int healthy_nodes = *(int *)private_data;
85 tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
86 ret = tdb_transaction_commit(ctdb_db->ltdb->tdb);
87 tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
89 DEBUG(DEBUG_ERR, ("Failed to commit transaction for db %s\n",
94 ret = ctdb_update_persistent_health(ctdb_db->ctdb, ctdb_db, NULL,
97 DEBUG(DEBUG_ERR, ("Failed to update persistent health for db %s\n",
105 a list of control requests waiting for a freeze lock child to get
108 struct ctdb_freeze_waiter {
109 struct ctdb_freeze_waiter *next, *prev;
110 struct ctdb_context *ctdb;
111 struct ctdb_req_control *c;
116 /* a handle to a freeze lock child process */
117 struct ctdb_freeze_handle {
118 struct ctdb_context *ctdb;
120 struct lock_request *lreq;
121 struct ctdb_freeze_waiter *waiters;
125 destroy a freeze handle
127 static int ctdb_freeze_handle_destructor(struct ctdb_freeze_handle *h)
129 struct ctdb_context *ctdb = h->ctdb;
131 DEBUG(DEBUG_ERR,("Release freeze handler for prio %u\n", h->priority));
133 /* cancel any pending transactions */
134 if (ctdb->freeze_transaction_started) {
135 ctdb_db_prio_iterator(ctdb, h->priority,
136 db_transaction_cancel_handler, NULL);
137 ctdb->freeze_transaction_started = false;
140 ctdb->freeze_mode[h->priority] = CTDB_FREEZE_NONE;
141 ctdb->freeze_handles[h->priority] = NULL;
147 called when the child writes its status to us
149 static void ctdb_freeze_lock_handler(void *private_data, bool locked)
151 struct ctdb_freeze_handle *h = talloc_get_type_abort(private_data,
152 struct ctdb_freeze_handle);
153 struct ctdb_freeze_waiter *w;
155 if (h->ctdb->freeze_mode[h->priority] == CTDB_FREEZE_FROZEN) {
156 DEBUG(DEBUG_INFO,("freeze child died - unfreezing\n"));
162 DEBUG(DEBUG_ERR,("Failed to get locks in ctdb_freeze_child\n"));
163 /* we didn't get the locks - destroy the handle */
168 h->ctdb->freeze_mode[h->priority] = CTDB_FREEZE_FROZEN;
170 /* notify the waiters */
171 if (h != h->ctdb->freeze_handles[h->priority]) {
172 DEBUG(DEBUG_ERR,("lockwait finished but h is not linked\n"));
174 while ((w = h->waiters)) {
176 DLIST_REMOVE(h->waiters, w);
182 destroy a waiter for a freeze mode change
184 static int ctdb_freeze_waiter_destructor(struct ctdb_freeze_waiter *w)
186 ctdb_request_control_reply(w->ctdb, w->c, NULL, w->status, NULL);
191 start the freeze process for a certain priority
193 void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority)
195 struct ctdb_freeze_handle *h;
197 if ((priority < 1) || (priority > NUM_DB_PRIORITIES)) {
198 DEBUG(DEBUG_ERR,(__location__ " Invalid db priority : %u\n", priority));
199 ctdb_fatal(ctdb, "Internal error");
202 if (ctdb->freeze_mode[priority] == CTDB_FREEZE_FROZEN) {
203 /* we're already frozen */
207 if (ctdb->freeze_handles[priority] != NULL) {
208 /* already trying to freeze */
212 DEBUG(DEBUG_ERR, ("Freeze priority %u\n", priority));
214 /* Stop any vacuuming going on: we don't want to wait. */
215 ctdb_stop_vacuuming(ctdb);
217 /* create freeze lock child */
218 h = talloc_zero(ctdb, struct ctdb_freeze_handle);
219 CTDB_NO_MEMORY_FATAL(ctdb, h);
221 h->priority = priority;
222 talloc_set_destructor(h, ctdb_freeze_handle_destructor);
224 h->lreq = ctdb_lock_alldb_prio(h, ctdb, priority, false,
225 ctdb_freeze_lock_handler, h);
226 CTDB_NO_MEMORY_FATAL(ctdb, h->lreq);
227 ctdb->freeze_handles[priority] = h;
228 ctdb->freeze_mode[priority] = CTDB_FREEZE_PENDING;
234 int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply)
236 struct ctdb_freeze_waiter *w;
239 priority = (uint32_t)c->srvid;
242 DEBUG(DEBUG_ERR,("Freeze priority 0 requested, remapping to priority 1\n"));
246 if ((priority < 1) || (priority > NUM_DB_PRIORITIES)) {
247 DEBUG(DEBUG_ERR,(__location__ " Invalid db priority : %u\n", priority));
251 if (ctdb->freeze_mode[priority] == CTDB_FREEZE_FROZEN) {
252 DEBUG(DEBUG_ERR, ("Freeze priority %u\n", priority));
253 /* we're already frozen */
257 ctdb_start_freeze(ctdb, priority);
259 /* add ourselves to list of waiters */
260 if (ctdb->freeze_handles[priority] == NULL) {
261 DEBUG(DEBUG_ERR,("No freeze lock handle when adding a waiter\n"));
265 w = talloc(ctdb->freeze_handles[priority], struct ctdb_freeze_waiter);
266 CTDB_NO_MEMORY(ctdb, w);
268 w->c = talloc_steal(w, c);
269 w->priority = priority;
271 talloc_set_destructor(w, ctdb_freeze_waiter_destructor);
272 DLIST_ADD(ctdb->freeze_handles[priority]->waiters, w);
274 /* we won't reply till later */
281 block until we are frozen, used during daemon startup
283 bool ctdb_blocking_freeze(struct ctdb_context *ctdb)
287 for (i=1; i<=NUM_DB_PRIORITIES; i++) {
288 ctdb_start_freeze(ctdb, i);
290 /* block until frozen */
291 while (ctdb->freeze_mode[i] == CTDB_FREEZE_PENDING) {
292 event_loop_once(ctdb->ev);
300 static void thaw_priority(struct ctdb_context *ctdb, uint32_t priority)
302 DEBUG(DEBUG_ERR,("Thawing priority %u\n", priority));
304 /* cancel any pending transactions */
305 if (ctdb->freeze_transaction_started) {
306 ctdb_db_prio_iterator(ctdb, priority,
307 db_transaction_cancel_handler, NULL);
308 ctdb->freeze_transaction_started = false;
311 if (ctdb->freeze_handles[priority] != NULL) {
312 talloc_free(ctdb->freeze_handles[priority]);
313 ctdb->freeze_handles[priority] = NULL;
320 int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority,
323 if (priority > NUM_DB_PRIORITIES) {
324 DEBUG(DEBUG_ERR,(__location__ " Invalid db priority : %u\n",
329 if (check_recmode && ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE) {
330 DEBUG(DEBUG_ERR, ("Failing to thaw databases while "
331 "recovery is active\n"));
337 for (i=1;i<=NUM_DB_PRIORITIES; i++) {
338 thaw_priority(ctdb, i);
341 thaw_priority(ctdb, priority);
344 ctdb_call_resend_all(ctdb);
350 start a transaction on all databases - used for recovery
352 int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id)
356 if (!ctdb_db_all_frozen(ctdb)) {
357 DEBUG(DEBUG_ERR, (__location__
358 " failing transaction start while not frozen\n"));
362 ret = ctdb_db_iterator(ctdb, db_transaction_start_handler,
363 &ctdb->freeze_transaction_started);
368 ctdb->freeze_transaction_started = true;
369 ctdb->freeze_transaction_id = id;
375 cancel a transaction for all databases - used for recovery
377 int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb)
379 DEBUG(DEBUG_ERR,(__location__ " recovery transaction cancelled called\n"));
381 ctdb_db_iterator(ctdb, db_transaction_cancel_handler, NULL);
382 ctdb->freeze_transaction_started = false;
388 commit transactions on all databases
390 int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id)
393 int healthy_nodes = 0;
396 if (!ctdb_db_all_frozen(ctdb)) {
397 DEBUG(DEBUG_ERR, (__location__
398 " failing transaction commit while not frozen\n"));
402 if (!ctdb->freeze_transaction_started) {
403 DEBUG(DEBUG_ERR,(__location__ " transaction not started\n"));
407 if (id != ctdb->freeze_transaction_id) {
408 DEBUG(DEBUG_ERR,(__location__ " incorrect transaction id 0x%x in commit\n", id));
412 DEBUG(DEBUG_DEBUG,(__location__ " num_nodes[%d]\n", ctdb->num_nodes));
413 for (i=0; i < ctdb->num_nodes; i++) {
414 DEBUG(DEBUG_DEBUG,(__location__ " node[%d].flags[0x%X]\n",
415 i, ctdb->nodes[i]->flags));
416 if (ctdb->nodes[i]->flags == 0) {
420 DEBUG(DEBUG_INFO,(__location__ " healthy_nodes[%d]\n", healthy_nodes));
422 ret = ctdb_db_iterator(ctdb, db_transaction_commit_handler,
425 DEBUG(DEBUG_ERR, ("Cancel all transactions\n"));
429 ctdb->freeze_transaction_started = false;
430 ctdb->freeze_transaction_id = 0;
435 /* cancel any pending transactions */
436 ctdb_db_iterator(ctdb, db_transaction_cancel_handler, NULL);
437 ctdb->freeze_transaction_started = false;
443 wipe a database - only possible when in a frozen transaction
445 int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata)
447 struct ctdb_control_wipe_database w = *(struct ctdb_control_wipe_database *)indata.dptr;
448 struct ctdb_db_context *ctdb_db;
450 ctdb_db = find_ctdb_db(ctdb, w.db_id);
452 DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%x\n", w.db_id));
456 if (ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_FROZEN) {
457 DEBUG(DEBUG_ERR,(__location__ " Failed transaction_start while not frozen\n"));
461 if (!ctdb->freeze_transaction_started) {
462 DEBUG(DEBUG_ERR,(__location__ " transaction not started\n"));
466 if (w.transaction_id != ctdb->freeze_transaction_id) {
467 DEBUG(DEBUG_ERR,(__location__ " incorrect transaction id 0x%x in commit\n", w.transaction_id));
471 if (tdb_wipe_all(ctdb_db->ltdb->tdb) != 0) {
472 DEBUG(DEBUG_ERR,(__location__ " Failed to wipe database for db '%s'\n",
477 if (!ctdb_db->persistent) {
478 talloc_free(ctdb_db->delete_queue);
479 ctdb_db->delete_queue = trbt_create(ctdb_db, 0);
480 if (ctdb_db->delete_queue == NULL) {
481 DEBUG(DEBUG_ERR, (__location__ " Failed to re-create "
482 "the vacuum tree.\n"));
490 bool ctdb_db_prio_frozen(struct ctdb_context *ctdb, uint32_t priority)
495 if (priority > NUM_DB_PRIORITIES) {
496 DEBUG(DEBUG_ERR, ("Invalid DB priority specified\n"));
500 if (ctdb->freeze_mode[priority] != CTDB_FREEZE_FROZEN) {
507 bool ctdb_db_all_frozen(struct ctdb_context *ctdb)
511 for (i=1; i<=NUM_DB_PRIORITIES; i++) {
512 if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) {