ctdb-util: Rename db_wrap to tdb_wrap and make it a build subsystem
[Samba.git] / ctdb / tools / ctdb_vacuum.c
blobae936824308a5af5cc29d995f73183e2c033aa82
1 /*
2 ctdb control tool - database vacuum
4 Copyright (C) Andrew Tridgell 2008
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 "includes.h"
21 #include "system/filesys.h"
22 #include "system/network.h"
23 #include "../include/ctdb_client.h"
24 #include "../include/ctdb_private.h"
25 #include "../common/rb_tree.h"
26 #include "lib/tdb_wrap/tdb_wrap.h"
28 /* should be tunable */
29 #define TIMELIMIT() timeval_current_ofs(10, 0)
32 struct vacuum_traverse_state {
33 bool error;
34 struct tdb_context *dest_db;
38 traverse function for repacking
40 static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
42 struct vacuum_traverse_state *state = (struct vacuum_traverse_state *)private;
43 if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
44 state->error = true;
45 return -1;
47 return 0;
51 repack a tdb
53 static int ctdb_repack_tdb(struct tdb_context *tdb)
55 struct tdb_context *tmp_db;
56 struct vacuum_traverse_state state;
58 if (tdb_transaction_start(tdb) != 0) {
59 DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction\n"));
60 return -1;
63 tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb),
64 TDB_INTERNAL|TDB_DISALLOW_NESTING,
65 O_RDWR|O_CREAT, 0);
66 if (tmp_db == NULL) {
67 DEBUG(DEBUG_ERR,(__location__ " Failed to create tmp_db\n"));
68 tdb_transaction_cancel(tdb);
69 return -1;
72 state.error = false;
73 state.dest_db = tmp_db;
75 if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) {
76 DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying out\n"));
77 tdb_transaction_cancel(tdb);
78 tdb_close(tmp_db);
79 return -1;
82 if (state.error) {
83 DEBUG(DEBUG_ERR,(__location__ " Error during traversal\n"));
84 tdb_transaction_cancel(tdb);
85 tdb_close(tmp_db);
86 return -1;
89 if (tdb_wipe_all(tdb) != 0) {
90 DEBUG(DEBUG_ERR,(__location__ " Failed to wipe database\n"));
91 tdb_transaction_cancel(tdb);
92 tdb_close(tmp_db);
93 return -1;
96 state.error = false;
97 state.dest_db = tdb;
99 if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) {
100 DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying back\n"));
101 tdb_transaction_cancel(tdb);
102 tdb_close(tmp_db);
103 return -1;
106 if (state.error) {
107 DEBUG(DEBUG_ERR,(__location__ " Error during second traversal\n"));
108 tdb_transaction_cancel(tdb);
109 tdb_close(tmp_db);
110 return -1;
113 tdb_close(tmp_db);
115 if (tdb_transaction_commit(tdb) != 0) {
116 DEBUG(DEBUG_ERR,(__location__ " Failed to commit\n"));
117 return -1;
120 return 0;
124 /* repack one database */
125 static int ctdb_repack_db(struct ctdb_context *ctdb, uint32_t db_id,
126 bool persistent, uint32_t repack_limit)
128 struct ctdb_db_context *ctdb_db;
129 const char *name;
130 int size;
132 if (ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, db_id, ctdb, &name) != 0) {
133 DEBUG(DEBUG_ERR,(__location__ " Failed to get name of db 0x%x\n", db_id));
134 return -1;
137 ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), name, persistent, 0);
138 if (ctdb_db == NULL) {
139 DEBUG(DEBUG_ERR,(__location__ " Failed to attach to database '%s'\n", name));
140 return -1;
143 size = tdb_freelist_size(ctdb_db->ltdb->tdb);
144 if (size == -1) {
145 DEBUG(DEBUG_ERR,(__location__ " Failed to get freelist size for '%s'\n", name));
146 return -1;
149 if (size <= repack_limit) {
150 return 0;
153 printf("Repacking %s with %u freelist entries\n", name, size);
155 if (ctdb_repack_tdb(ctdb_db->ltdb->tdb) != 0) {
156 DEBUG(DEBUG_ERR,(__location__ " Failed to repack '%s'\n", name));
157 return -1;
160 return 0;
165 repack all our databases
167 int ctdb_repack(struct ctdb_context *ctdb, int argc, const char **argv)
169 struct ctdb_dbid_map *dbmap=NULL;
170 int ret, i;
171 /* a reasonable default limit to prevent us using too much memory */
172 uint32_t repack_limit = 10000;
174 if (argc > 0) {
175 repack_limit = atoi(argv[0]);
178 ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &dbmap);
179 if (ret != 0) {
180 DEBUG(DEBUG_ERR, ("Unable to get dbids from local node\n"));
181 return ret;
184 for (i=0;i<dbmap->num;i++) {
185 if (ctdb_repack_db(ctdb, dbmap->dbs[i].dbid,
186 dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT, repack_limit) != 0) {
187 DEBUG(DEBUG_ERR,("Failed to repack db 0x%x\n", dbmap->dbs[i].dbid));
188 return -1;
192 return 0;