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/>.
20 #include "system/network.h"
21 #include "system/filesys.h"
22 #include "system/wait.h"
27 #include "lib/tdb_wrap/tdb_wrap.h"
28 #include "lib/util/dlinklist.h"
29 #include "lib/util/debug.h"
31 #include "ctdb_private.h"
33 #include "common/rb_tree.h"
34 #include "common/common.h"
35 #include "common/logging.h"
38 * Cancel a transaction on database
40 static int db_transaction_cancel_handler(struct ctdb_db_context
*ctdb_db
,
45 tdb_add_flags(ctdb_db
->ltdb
->tdb
, TDB_NOLOCK
);
46 ret
= tdb_transaction_cancel(ctdb_db
->ltdb
->tdb
);
48 DEBUG(DEBUG_ERR
, ("Failed to cancel transaction for db %s\n",
51 tdb_remove_flags(ctdb_db
->ltdb
->tdb
, TDB_NOLOCK
);
56 * Start a transaction on database
58 static int db_transaction_start_handler(struct ctdb_db_context
*ctdb_db
,
61 bool freeze_transaction_started
= *(bool *)private_data
;
64 tdb_add_flags(ctdb_db
->ltdb
->tdb
, TDB_NOLOCK
);
65 if (freeze_transaction_started
) {
66 ret
= tdb_transaction_cancel(ctdb_db
->ltdb
->tdb
);
69 ("Failed to cancel transaction for db %s\n",
73 ret
= tdb_transaction_start(ctdb_db
->ltdb
->tdb
);
74 tdb_remove_flags(ctdb_db
->ltdb
->tdb
, TDB_NOLOCK
);
76 DEBUG(DEBUG_ERR
, ("Failed to start transaction for db %s\n",
84 * Commit a transaction on database
86 static int db_transaction_commit_handler(struct ctdb_db_context
*ctdb_db
,
89 int healthy_nodes
= *(int *)private_data
;
92 tdb_add_flags(ctdb_db
->ltdb
->tdb
, TDB_NOLOCK
);
93 ret
= tdb_transaction_commit(ctdb_db
->ltdb
->tdb
);
94 tdb_remove_flags(ctdb_db
->ltdb
->tdb
, TDB_NOLOCK
);
96 DEBUG(DEBUG_ERR
, ("Failed to commit transaction for db %s\n",
101 ret
= ctdb_update_persistent_health(ctdb_db
->ctdb
, ctdb_db
, NULL
,
104 DEBUG(DEBUG_ERR
, ("Failed to update persistent health for db %s\n",
110 /* a list of control requests waiting for db freeze */
111 struct ctdb_db_freeze_waiter
{
112 struct ctdb_db_freeze_waiter
*next
, *prev
;
113 struct ctdb_context
*ctdb
;
118 /* a handle to a db freeze lock child process */
119 struct ctdb_db_freeze_handle
{
120 struct ctdb_db_context
*ctdb_db
;
121 struct lock_request
*lreq
;
122 struct ctdb_db_freeze_waiter
*waiters
;
126 * Called when freeing database freeze handle
128 static int ctdb_db_freeze_handle_destructor(struct ctdb_db_freeze_handle
*h
)
130 struct ctdb_db_context
*ctdb_db
= h
->ctdb_db
;
132 DEBUG(DEBUG_ERR
, ("Release freeze handle for db %s\n",
135 /* Cancel any pending transactions */
136 if (ctdb_db
->freeze_transaction_started
) {
137 db_transaction_cancel_handler(ctdb_db
, NULL
);
138 ctdb_db
->freeze_transaction_started
= false;
140 ctdb_db
->freeze_mode
= CTDB_FREEZE_NONE
;
141 ctdb_db
->freeze_handle
= NULL
;
143 talloc_free(h
->lreq
);
148 * Called when a database is frozen
150 static void ctdb_db_freeze_handler(void *private_data
, bool locked
)
152 struct ctdb_db_freeze_handle
*h
= talloc_get_type_abort(
153 private_data
, struct ctdb_db_freeze_handle
);
154 struct ctdb_db_freeze_waiter
*w
;
156 if (h
->ctdb_db
->freeze_mode
== CTDB_FREEZE_FROZEN
) {
157 DEBUG(DEBUG_ERR
, ("Freeze db child died - unfreezing\n"));
158 h
->ctdb_db
->freeze_mode
= CTDB_FREEZE_NONE
;
164 DEBUG(DEBUG_ERR
, ("Failed to get db lock for %s\n",
165 h
->ctdb_db
->db_name
));
166 h
->ctdb_db
->freeze_mode
= CTDB_FREEZE_NONE
;
171 h
->ctdb_db
->freeze_mode
= CTDB_FREEZE_FROZEN
;
173 /* notify the waiters */
174 while ((w
= h
->waiters
) != NULL
) {
176 DLIST_REMOVE(h
->waiters
, w
);
182 * Start freeze process for a database
184 static void ctdb_start_db_freeze(struct ctdb_db_context
*ctdb_db
)
186 struct ctdb_db_freeze_handle
*h
;
188 if (ctdb_db
->freeze_mode
== CTDB_FREEZE_FROZEN
) {
192 if (ctdb_db
->freeze_handle
!= NULL
) {
196 DEBUG(DEBUG_ERR
, ("Freeze db: %s\n", ctdb_db
->db_name
));
198 ctdb_stop_vacuuming(ctdb_db
->ctdb
);
200 h
= talloc_zero(ctdb_db
, struct ctdb_db_freeze_handle
);
201 CTDB_NO_MEMORY_FATAL(ctdb_db
->ctdb
, h
);
203 h
->ctdb_db
= ctdb_db
;
204 h
->lreq
= ctdb_lock_db(h
, ctdb_db
, false, ctdb_db_freeze_handler
, h
);
205 CTDB_NO_MEMORY_FATAL(ctdb_db
->ctdb
, h
->lreq
);
206 talloc_set_destructor(h
, ctdb_db_freeze_handle_destructor
);
208 ctdb_db
->freeze_handle
= h
;
209 ctdb_db
->freeze_mode
= CTDB_FREEZE_PENDING
;
213 * Reply to a waiter for db freeze
215 static int ctdb_db_freeze_waiter_destructor(struct ctdb_db_freeze_waiter
*w
)
217 /* 'c' pointer is talloc_memdup(), so cannot use talloc_get_type */
218 struct ctdb_req_control_old
*c
=
219 (struct ctdb_req_control_old
*)w
->private_data
;
221 ctdb_request_control_reply(w
->ctdb
, c
, NULL
, w
->status
, NULL
);
228 int32_t ctdb_control_db_freeze(struct ctdb_context
*ctdb
,
229 struct ctdb_req_control_old
*c
,
233 struct ctdb_db_context
*ctdb_db
;
234 struct ctdb_db_freeze_waiter
*w
;
236 ctdb_db
= find_ctdb_db(ctdb
, db_id
);
237 if (ctdb_db
== NULL
) {
238 DEBUG(DEBUG_ERR
, ("Freeze db for unknown dbid 0x%08x\n", db_id
));
242 if (ctdb_db
->freeze_mode
== CTDB_FREEZE_FROZEN
) {
243 DEBUG(DEBUG_ERR
, ("Freeze db: %s frozen\n", ctdb_db
->db_name
));
247 ctdb_start_db_freeze(ctdb_db
);
249 /* add ourselves to the list of waiters */
250 w
= talloc(ctdb_db
->freeze_handle
, struct ctdb_db_freeze_waiter
);
251 CTDB_NO_MEMORY(ctdb
, w
);
253 w
->private_data
= talloc_steal(w
, c
);
255 talloc_set_destructor(w
, ctdb_db_freeze_waiter_destructor
);
256 DLIST_ADD(ctdb_db
->freeze_handle
->waiters
, w
);
265 int32_t ctdb_control_db_thaw(struct ctdb_context
*ctdb
, uint32_t db_id
)
267 struct ctdb_db_context
*ctdb_db
;
269 ctdb_db
= find_ctdb_db(ctdb
, db_id
);
270 if (ctdb_db
== NULL
) {
271 DEBUG(DEBUG_ERR
, ("Thaw db for unknown dbid 0x%08x\n", db_id
));
275 DEBUG(DEBUG_ERR
, ("Thaw db: %s generation %u\n", ctdb_db
->db_name
,
276 ctdb_db
->generation
));
278 TALLOC_FREE(ctdb_db
->freeze_handle
);
279 ctdb_call_resend_db(ctdb_db
);
285 a list of control requests waiting for a freeze lock child to get
288 struct ctdb_freeze_waiter
{
289 struct ctdb_freeze_waiter
*next
, *prev
;
290 struct ctdb_context
*ctdb
;
291 struct ctdb_req_control_old
*c
;
295 /* a handle to a freeze lock child process */
296 struct ctdb_freeze_handle
{
297 struct ctdb_context
*ctdb
;
298 unsigned int num_total
, num_locked
, num_failed
;
299 struct ctdb_freeze_waiter
*waiters
;
302 static int db_thaw(struct ctdb_db_context
*ctdb_db
, void *private_data
)
304 talloc_free(ctdb_db
->freeze_handle
);
309 destroy a freeze handle
311 static int ctdb_freeze_handle_destructor(struct ctdb_freeze_handle
*h
)
313 struct ctdb_context
*ctdb
= h
->ctdb
;
315 DEBUG(DEBUG_ERR
,("Release freeze handle\n"));
317 /* cancel any pending transactions */
318 if (ctdb
->freeze_transaction_started
) {
319 ctdb_db_iterator(ctdb
, db_transaction_cancel_handler
, NULL
);
320 ctdb
->freeze_transaction_started
= false;
323 ctdb_db_iterator(ctdb
, db_thaw
, NULL
);
325 ctdb
->freeze_mode
= CTDB_FREEZE_NONE
;
326 ctdb
->freeze_handle
= NULL
;
332 called when the child writes its status to us
334 static void ctdb_freeze_lock_handler(void *private_data
, bool locked
)
336 struct ctdb_freeze_handle
*h
= talloc_get_type_abort(private_data
,
337 struct ctdb_freeze_handle
);
338 struct ctdb_freeze_waiter
*w
;
340 if (h
->ctdb
->freeze_mode
== CTDB_FREEZE_FROZEN
) {
341 DEBUG(DEBUG_INFO
,("freeze child died - unfreezing\n"));
347 DEBUG(DEBUG_ERR
,("Failed to get locks in ctdb_freeze_child\n"));
348 /* we didn't get the locks - destroy the handle */
353 h
->ctdb
->freeze_mode
= CTDB_FREEZE_FROZEN
;
355 /* notify the waiters */
356 if (h
!= h
->ctdb
->freeze_handle
) {
357 DEBUG(DEBUG_ERR
,("lockwait finished but h is not linked\n"));
359 while ((w
= h
->waiters
)) {
361 DLIST_REMOVE(h
->waiters
, w
);
367 * When single database is frozen
369 static int db_freeze_waiter_destructor(struct ctdb_db_freeze_waiter
*w
)
371 struct ctdb_freeze_handle
*h
= talloc_get_type_abort(
372 w
->private_data
, struct ctdb_freeze_handle
);
374 if (w
->status
== 0) {
380 /* Call ctdb_freeze_lock_handler() only when the status of all
381 * databases is known.
383 if (h
->num_locked
+ h
->num_failed
== h
->num_total
) {
386 if (h
->num_locked
== h
->num_total
) {
391 ctdb_freeze_lock_handler(h
, locked
);
397 * Count the number of databases
399 static int db_count(struct ctdb_db_context
*ctdb_db
, void *private_data
)
401 int *count
= (int *)private_data
;
409 * Freeze a single database
411 static int db_freeze(struct ctdb_db_context
*ctdb_db
, void *private_data
)
413 struct ctdb_freeze_handle
*h
= talloc_get_type_abort(
414 private_data
, struct ctdb_freeze_handle
);
415 struct ctdb_db_freeze_waiter
*w
;
417 ctdb_start_db_freeze(ctdb_db
);
419 w
= talloc(ctdb_db
->freeze_handle
, struct ctdb_db_freeze_waiter
);
420 CTDB_NO_MEMORY(h
->ctdb
, w
);
424 talloc_set_destructor(w
, db_freeze_waiter_destructor
);
426 if (ctdb_db
->freeze_mode
== CTDB_FREEZE_FROZEN
) {
427 /* Early return if already frozen */
433 DLIST_ADD(ctdb_db
->freeze_handle
->waiters
, w
);
439 start the freeze process for a certain priority
441 static void ctdb_start_freeze(struct ctdb_context
*ctdb
)
443 struct ctdb_freeze_handle
*h
;
446 if (ctdb
->freeze_mode
== CTDB_FREEZE_FROZEN
) {
450 * Check if all the databases are frozen
452 * It's possible that the databases can get attached after
453 * initial freeze. This typically happens during startup as
454 * CTDB will only attach persistent databases and go in to
455 * startup freeze. The recovery master during recovery will
456 * attach all the missing databases.
459 h
= ctdb
->freeze_handle
;
461 ctdb
->freeze_mode
= CTDB_FREEZE_NONE
;
465 ret
= ctdb_db_iterator(ctdb
, db_count
, &count
);
467 TALLOC_FREE(ctdb
->freeze_handle
);
468 ctdb
->freeze_mode
= CTDB_FREEZE_NONE
;
472 if (count
!= h
->num_total
) {
473 DEBUG(DEBUG_ERR
, ("Freeze all: incremental\n"));
475 h
->num_total
= count
;
479 ctdb
->freeze_mode
= CTDB_FREEZE_PENDING
;
481 ret
= ctdb_db_iterator(ctdb
, db_freeze
, h
);
483 TALLOC_FREE(ctdb
->freeze_handle
);
484 ctdb
->freeze_mode
= CTDB_FREEZE_NONE
;
490 if (ctdb
->freeze_handle
!= NULL
) {
491 /* already trying to freeze */
495 DEBUG(DEBUG_ERR
, ("Freeze all\n"));
497 /* Stop any vacuuming going on: we don't want to wait. */
498 ctdb_stop_vacuuming(ctdb
);
500 /* create freeze lock children for each database */
501 h
= talloc_zero(ctdb
, struct ctdb_freeze_handle
);
502 CTDB_NO_MEMORY_FATAL(ctdb
, h
);
504 talloc_set_destructor(h
, ctdb_freeze_handle_destructor
);
505 ctdb
->freeze_handle
= h
;
507 ret
= ctdb_db_iterator(ctdb
, db_count
, &h
->num_total
);
513 ctdb
->freeze_mode
= CTDB_FREEZE_PENDING
;
515 ret
= ctdb_db_iterator(ctdb
, db_freeze
, h
);
521 if (h
->num_total
== 0) {
522 ctdb
->freeze_mode
= CTDB_FREEZE_FROZEN
;
527 destroy a waiter for a freeze mode change
529 static int ctdb_freeze_waiter_destructor(struct ctdb_freeze_waiter
*w
)
531 ctdb_request_control_reply(w
->ctdb
, w
->c
, NULL
, w
->status
, NULL
);
536 freeze all the databases
538 int32_t ctdb_control_freeze(struct ctdb_context
*ctdb
,
539 struct ctdb_req_control_old
*c
, bool *async_reply
)
541 struct ctdb_freeze_waiter
*w
;
543 ctdb_start_freeze(ctdb
);
545 if (ctdb
->freeze_mode
== CTDB_FREEZE_FROZEN
) {
546 DEBUG(DEBUG_ERR
, ("Freeze all: frozen\n"));
547 /* we're already frozen */
551 if (ctdb
->freeze_handle
== NULL
) {
552 DEBUG(DEBUG_ERR
,("No freeze lock handle when adding a waiter\n"));
556 /* If there are no databases, we are done. */
557 if (ctdb
->freeze_handle
->num_total
== 0) {
561 /* add ourselves to list of waiters */
562 w
= talloc(ctdb
->freeze_handle
, struct ctdb_freeze_waiter
);
563 CTDB_NO_MEMORY(ctdb
, w
);
565 w
->c
= talloc_steal(w
, c
);
567 talloc_set_destructor(w
, ctdb_freeze_waiter_destructor
);
568 DLIST_ADD(ctdb
->freeze_handle
->waiters
, w
);
570 /* we won't reply till later */
576 static int db_freeze_block(struct ctdb_db_context
*ctdb_db
, void *private_data
)
578 struct tevent_context
*ev
= (struct tevent_context
*)private_data
;
580 ctdb_start_db_freeze(ctdb_db
);
582 while (ctdb_db
->freeze_mode
== CTDB_FREEZE_PENDING
) {
583 tevent_loop_once(ev
);
586 if (ctdb_db
->freeze_mode
!= CTDB_FREEZE_FROZEN
) {
594 block until we are frozen, used during daemon startup
596 bool ctdb_blocking_freeze(struct ctdb_context
*ctdb
)
600 ret
= ctdb_db_iterator(ctdb
, db_freeze_block
, ctdb
->ev
);
611 int32_t ctdb_control_thaw(struct ctdb_context
*ctdb
, bool check_recmode
)
613 if (check_recmode
&& ctdb
->recovery_mode
== CTDB_RECOVERY_ACTIVE
) {
614 DEBUG(DEBUG_ERR
, ("Failing to thaw databases while "
615 "recovery is active\n"));
619 DEBUG(DEBUG_ERR
,("Thawing all\n"));
621 /* cancel any pending transactions */
622 if (ctdb
->freeze_transaction_started
) {
623 ctdb_db_iterator(ctdb
, db_transaction_cancel_handler
, NULL
);
624 ctdb
->freeze_transaction_started
= false;
627 ctdb_db_iterator(ctdb
, db_thaw
, NULL
);
628 TALLOC_FREE(ctdb
->freeze_handle
);
630 ctdb_call_resend_all(ctdb
);
635 * Database transaction wrappers
637 * These functions are wrappers around transaction start/cancel/commit handlers.
640 struct db_start_transaction_state
{
641 uint32_t transaction_id
;
642 bool transaction_started
;
645 static int db_start_transaction(struct ctdb_db_context
*ctdb_db
,
648 struct db_start_transaction_state
*state
=
649 (struct db_start_transaction_state
*)private_data
;
651 bool transaction_started
;
653 if (ctdb_db
->freeze_mode
!= CTDB_FREEZE_FROZEN
) {
655 ("Database %s not frozen, cannot start transaction\n",
660 transaction_started
= state
->transaction_started
&
661 ctdb_db
->freeze_transaction_started
;
663 ret
= db_transaction_start_handler(ctdb_db
,
664 &transaction_started
);
669 ctdb_db
->freeze_transaction_started
= true;
670 ctdb_db
->freeze_transaction_id
= state
->transaction_id
;
675 static int db_cancel_transaction(struct ctdb_db_context
*ctdb_db
,
680 ret
= db_transaction_cancel_handler(ctdb_db
, private_data
);
685 ctdb_db
->freeze_transaction_started
= false;
690 struct db_commit_transaction_state
{
691 uint32_t transaction_id
;
695 static int db_commit_transaction(struct ctdb_db_context
*ctdb_db
,
698 struct db_commit_transaction_state
*state
=
699 (struct db_commit_transaction_state
*)private_data
;
702 if (ctdb_db
->freeze_mode
!= CTDB_FREEZE_FROZEN
) {
704 ("Database %s not frozen, cannot commit transaction\n",
709 if (!ctdb_db
->freeze_transaction_started
) {
710 DEBUG(DEBUG_ERR
, ("Transaction not started on %s\n",
715 if (ctdb_db
->freeze_transaction_id
!= state
->transaction_id
) {
717 ("Incorrect transaction commit id 0x%08x for %s\n",
718 state
->transaction_id
, ctdb_db
->db_name
));
722 ret
= db_transaction_commit_handler(ctdb_db
, &state
->healthy_nodes
);
727 ctdb_db
->freeze_transaction_started
= false;
728 ctdb_db
->freeze_transaction_id
= 0;
729 ctdb_db
->generation
= state
->transaction_id
;
734 * Start a transaction on a database - used for db recovery
736 int32_t ctdb_control_db_transaction_start(struct ctdb_context
*ctdb
,
739 struct ctdb_transdb
*w
=
740 (struct ctdb_transdb
*)indata
.dptr
;
741 struct ctdb_db_context
*ctdb_db
;
742 struct db_start_transaction_state state
;
744 ctdb_db
= find_ctdb_db(ctdb
, w
->db_id
);
745 if (ctdb_db
== NULL
) {
747 ("Transaction start for unknown dbid 0x%08x\n",
752 state
.transaction_id
= w
->tid
;
753 state
.transaction_started
= true;
755 return db_start_transaction(ctdb_db
, &state
);
759 * Cancel a transaction on a database - used for db recovery
761 int32_t ctdb_control_db_transaction_cancel(struct ctdb_context
*ctdb
,
764 uint32_t db_id
= *(uint32_t *)indata
.dptr
;
765 struct ctdb_db_context
*ctdb_db
;
767 ctdb_db
= find_ctdb_db(ctdb
, db_id
);
768 if (ctdb_db
== NULL
) {
770 ("Transaction cancel for unknown dbid 0x%08x\n", db_id
));
774 DEBUG(DEBUG_ERR
, ("Recovery db transaction cancelled for %s\n",
777 return db_cancel_transaction(ctdb_db
, NULL
);
781 * Commit a transaction on a database - used for db recovery
783 int32_t ctdb_control_db_transaction_commit(struct ctdb_context
*ctdb
,
786 struct ctdb_transdb
*w
=
787 (struct ctdb_transdb
*)indata
.dptr
;
788 struct ctdb_db_context
*ctdb_db
;
789 struct db_commit_transaction_state state
;
790 int healthy_nodes
, i
;
792 ctdb_db
= find_ctdb_db(ctdb
, w
->db_id
);
793 if (ctdb_db
== NULL
) {
795 ("Transaction commit for unknown dbid 0x%08x\n",
801 for (i
=0; i
< ctdb
->num_nodes
; i
++) {
802 if (ctdb
->nodes
[i
]->flags
== 0) {
807 state
.transaction_id
= w
->tid
;
808 state
.healthy_nodes
= healthy_nodes
;
810 return db_commit_transaction(ctdb_db
, &state
);
814 wipe a database - only possible when in a frozen transaction
816 int32_t ctdb_control_wipe_database(struct ctdb_context
*ctdb
, TDB_DATA indata
)
818 struct ctdb_transdb w
= *(struct ctdb_transdb
*)indata
.dptr
;
819 struct ctdb_db_context
*ctdb_db
;
821 ctdb_db
= find_ctdb_db(ctdb
, w
.db_id
);
823 DEBUG(DEBUG_ERR
,(__location__
" Unknown db 0x%x\n", w
.db_id
));
827 if (ctdb_db
->freeze_mode
!= CTDB_FREEZE_FROZEN
) {
828 DEBUG(DEBUG_ERR
,(__location__
" Failed transaction_start while not frozen\n"));
832 if (!ctdb_db
->freeze_transaction_started
) {
833 DEBUG(DEBUG_ERR
,(__location__
" transaction not started\n"));
837 if (w
.tid
!= ctdb_db
->freeze_transaction_id
) {
838 DEBUG(DEBUG_ERR
,(__location__
" incorrect transaction id 0x%x in commit\n", w
.tid
));
842 if (tdb_wipe_all(ctdb_db
->ltdb
->tdb
) != 0) {
843 DEBUG(DEBUG_ERR
,(__location__
" Failed to wipe database for db '%s'\n",
848 if (!ctdb_db
->persistent
) {
849 talloc_free(ctdb_db
->delete_queue
);
850 ctdb_db
->delete_queue
= trbt_create(ctdb_db
, 0);
851 if (ctdb_db
->delete_queue
== NULL
) {
852 DEBUG(DEBUG_ERR
, (__location__
" Failed to re-create "
853 "the vacuum tree.\n"));
861 bool ctdb_db_frozen(struct ctdb_db_context
*ctdb_db
)
863 if (ctdb_db
->freeze_mode
!= CTDB_FREEZE_FROZEN
) {
870 bool ctdb_db_all_frozen(struct ctdb_context
*ctdb
)
872 if (ctdb
->freeze_mode
!= CTDB_FREEZE_FROZEN
) {