4 Copyright (C) Ronnie Sahlberg 2009
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 "lib/events/events.h"
22 #include "lib/tdb/include/tdb.h"
23 #include "system/network.h"
24 #include "system/filesys.h"
25 #include "system/dir.h"
26 #include "../include/ctdb_private.h"
28 #include "lib/util/dlinklist.h"
29 #include "lib/events/events.h"
30 #include "../include/ctdb_private.h"
33 enum vacuum_child_status { VACUUM_RUNNING, VACUUM_OK, VACUUM_ERROR, VACUUM_TIMEOUT};
35 struct ctdb_vacuum_child_context {
36 struct ctdb_vacuum_handle *vacuum_handle;
39 enum vacuum_child_status status;
40 struct timeval start_time;
43 struct ctdb_vacuum_handle {
44 struct ctdb_db_context *ctdb_db;
45 struct ctdb_vacuum_child_context *child_ctx;
49 static void ctdb_vacuum_event(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data);
51 struct traverse_state {
53 struct tdb_context *dest_db;
57 traverse function for repacking
59 static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
61 struct traverse_state *state = (struct traverse_state *)private;
62 if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
72 static int ctdb_repack_tdb(struct tdb_context *tdb, TALLOC_CTX *mem_ctx)
74 struct tdb_context *tmp_db;
75 struct traverse_state *state;
77 state = talloc(mem_ctx, struct traverse_state);
79 DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
83 if (tdb_transaction_start(tdb) != 0) {
84 DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction\n"));
88 tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb), TDB_INTERNAL, O_RDWR|O_CREAT, 0);
90 DEBUG(DEBUG_ERR,(__location__ " Failed to create tmp_db\n"));
91 tdb_transaction_cancel(tdb);
96 state->dest_db = tmp_db;
98 if (tdb_traverse_read(tdb, repack_traverse, state) == -1) {
99 DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying out\n"));
100 tdb_transaction_cancel(tdb);
106 DEBUG(DEBUG_ERR,(__location__ " Error during traversal\n"));
107 tdb_transaction_cancel(tdb);
112 if (tdb_wipe_all(tdb) != 0) {
113 DEBUG(DEBUG_ERR,(__location__ " Failed to wipe database\n"));
114 tdb_transaction_cancel(tdb);
119 state->error = false;
120 state->dest_db = tdb;
122 if (tdb_traverse_read(tmp_db, repack_traverse, state) == -1) {
123 DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying back\n"));
124 tdb_transaction_cancel(tdb);
130 DEBUG(DEBUG_ERR,(__location__ " Error during second traversal\n"));
131 tdb_transaction_cancel(tdb);
138 if (tdb_transaction_commit(tdb) != 0) {
139 DEBUG(DEBUG_ERR,(__location__ " Failed to commit\n"));
147 static int ctdb_repack_db(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx)
149 uint32_t repack_limit = ctdb_db->ctdb->tunable.repack_limit;
150 const char *name = ctdb_db->db_name;
151 int size = tdb_freelist_size(ctdb_db->ltdb->tdb);
154 DEBUG(DEBUG_ERR,(__location__ " Failed to get freelist size for '%s'\n", name));
158 if (size <= repack_limit) {
162 DEBUG(DEBUG_ERR,("Repacking %s with %u freelist entries\n", name, size));
164 if (ctdb_repack_tdb(ctdb_db->ltdb->tdb, mem_ctx) != 0) {
165 DEBUG(DEBUG_ERR,(__location__ " Failed to repack '%s'\n", name));
172 static int vacuum_child_destructor(struct ctdb_vacuum_child_context *child_ctx)
174 double l = timeval_elapsed(&child_ctx->start_time);
175 struct ctdb_db_context *ctdb_db = child_ctx->vacuum_handle->ctdb_db;
176 struct ctdb_context *ctdb = ctdb_db->ctdb;
178 DEBUG(DEBUG_ERR,("Vacuuming took %.3f seconds for database %s\n", l, ctdb_db->db_name));
180 if (child_ctx->child_pid != -1) {
181 kill(child_ctx->child_pid, SIGKILL);
184 /* here calculate a new interval */
185 /* child_ctx->status */
187 DEBUG(DEBUG_ERR, ("Start new vacuum event for %s\n", ctdb_db->db_name));
189 event_add_timed(ctdb->ev, child_ctx->vacuum_handle, timeval_current_ofs(ctdb->tunable.vacuum_default_interval, 0), ctdb_vacuum_event, child_ctx->vacuum_handle);
195 * this event is generated when a vacuum child process times out
197 static void vacuum_child_timeout(struct event_context *ev, struct timed_event *te,
198 struct timeval t, void *private_data)
200 struct ctdb_vacuum_child_context *child_ctx = talloc_get_type(private_data, struct ctdb_vacuum_child_context);
202 DEBUG(DEBUG_ERR,("Vacuuming child process timed out for db %s\n", child_ctx->vacuum_handle->ctdb_db->db_name));
204 child_ctx->status = VACUUM_TIMEOUT;
206 talloc_free(child_ctx);
211 * this event is generated when a vacuum child process has completed
213 static void vacuum_child_handler(struct event_context *ev, struct fd_event *fde,
214 uint16_t flags, void *private_data)
216 struct ctdb_vacuum_child_context *child_ctx = talloc_get_type(private_data, struct ctdb_vacuum_child_context);
220 DEBUG(DEBUG_ERR,("Vacuuming child finished for db %s\n", child_ctx->vacuum_handle->ctdb_db->db_name));
222 child_ctx->child_pid = -1;
224 ret = read(child_ctx->fd[0], &c, 1);
225 if (ret != 1 || c != 0) {
226 child_ctx->status = VACUUM_ERROR;
227 DEBUG(DEBUG_ERR, ("A vacuum child process failed with an error for database %s. ret=%d c=%d\n", child_ctx->vacuum_handle->ctdb_db->db_name, ret, c));
229 child_ctx->status = VACUUM_OK;
232 talloc_free(child_ctx);
236 * this event is called every time we need to start a new vacuum process
239 ctdb_vacuum_event(struct event_context *ev, struct timed_event *te,
240 struct timeval t, void *private_data)
242 struct ctdb_vacuum_handle *vacuum_handle = talloc_get_type(private_data, struct ctdb_vacuum_handle);
243 struct ctdb_db_context *ctdb_db = vacuum_handle->ctdb_db;
244 struct ctdb_context *ctdb = ctdb_db->ctdb;
245 struct ctdb_vacuum_child_context *child_ctx;
248 DEBUG(DEBUG_ERR,("Start a vacuuming child process for db %s\n", ctdb_db->db_name));
250 /* we dont vacuum if we are in recovery mode */
251 if (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE) {
252 event_add_timed(ctdb->ev, vacuum_handle, timeval_current_ofs(ctdb->tunable.vacuum_default_interval, 0), ctdb_vacuum_event, vacuum_handle);
257 child_ctx = talloc(vacuum_handle, struct ctdb_vacuum_child_context);
258 if (child_ctx == NULL) {
259 DEBUG(DEBUG_CRIT, (__location__ " Failed to allocate child context for vacuuming of %s\n", ctdb_db->db_name));
260 ctdb_fatal(ctdb, "Out of memory when crating vacuum child context. Shutting down\n");
264 ret = pipe(child_ctx->fd);
266 talloc_free(child_ctx);
267 DEBUG(DEBUG_ERR, ("Failed to create pipe for vacuum child process.\n"));
268 event_add_timed(ctdb->ev, vacuum_handle, timeval_current_ofs(ctdb->tunable.vacuum_default_interval, 0), ctdb_vacuum_event, vacuum_handle);
272 child_ctx->child_pid = fork();
273 if (child_ctx->child_pid == (pid_t)-1) {
274 close(child_ctx->fd[0]);
275 close(child_ctx->fd[1]);
276 talloc_free(child_ctx);
277 DEBUG(DEBUG_ERR, ("Failed to fork vacuum child process.\n"));
278 event_add_timed(ctdb->ev, vacuum_handle, timeval_current_ofs(ctdb->tunable.vacuum_default_interval, 0), ctdb_vacuum_event, vacuum_handle);
283 if (child_ctx->child_pid == 0) {
285 close(child_ctx->fd[0]);
288 * repack the db; next patch will include vacuuming here
290 cc = ctdb_repack_db(ctdb_db, child_ctx);
292 write(child_ctx->fd[1], &cc, 1);
296 set_close_on_exec(child_ctx->fd[0]);
297 close(child_ctx->fd[1]);
299 child_ctx->status = VACUUM_RUNNING;
300 child_ctx->start_time = timeval_current();
302 talloc_set_destructor(child_ctx, vacuum_child_destructor);
304 event_add_timed(ctdb->ev, child_ctx,
305 timeval_current_ofs(ctdb->tunable.vacuum_max_run_time, 0),
306 vacuum_child_timeout, child_ctx);
308 event_add_fd(ctdb->ev, child_ctx, child_ctx->fd[0],
309 EVENT_FD_READ|EVENT_FD_AUTOCLOSE,
310 vacuum_child_handler,
313 vacuum_handle->child_ctx = child_ctx;
314 child_ctx->vacuum_handle = vacuum_handle;
318 /* this function initializes the vacuuming context for a database
319 * starts the vacuuming events
321 int ctdb_vacuum_init(struct ctdb_db_context *ctdb_db)
323 struct ctdb_context *ctdb = ctdb_db->ctdb;
325 DEBUG(DEBUG_ERR,("Start vacuuming process for database %s\n", ctdb_db->db_name));
327 ctdb_db->vacuum_handle = talloc(ctdb_db, struct ctdb_vacuum_handle);
328 CTDB_NO_MEMORY(ctdb, ctdb_db->vacuum_handle);
330 ctdb_db->vacuum_handle->ctdb_db = ctdb_db;
332 event_add_timed(ctdb->ev, ctdb_db->vacuum_handle, timeval_current_ofs(ctdb->tunable.vacuum_default_interval, 0), ctdb_vacuum_event, ctdb_db->vacuum_handle);