Remove explicit include of lib/tevent/tevent.h.
[amitay/samba.git] / ctdb / tools / ctdb_vacuum.c
1 /* 
2    ctdb control tool - database vacuum 
3
4    Copyright (C) Andrew Tridgell  2008
5
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.
10    
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.
15    
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/>.
18 */
19
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 "db_wrap.h"
27
28 /* should be tunable */
29 #define TIMELIMIT() timeval_current_ofs(10, 0)
30
31
32 /*
33   vacuum all our databases
34  */
35 int ctdb_vacuum(struct ctdb_context *ctdb, int argc, const char **argv)
36 {
37         printf("\"ctdb vacuum\" is not implemented any more.\n");
38         return 0;
39 }
40
41 struct vacuum_traverse_state {
42         bool error;
43         struct tdb_context *dest_db;
44 };
45
46 /*
47   traverse function for repacking
48  */
49 static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
50 {
51         struct vacuum_traverse_state *state = (struct vacuum_traverse_state *)private;
52         if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
53                 state->error = true;
54                 return -1;
55         }
56         return 0;
57 }
58
59 /*
60   repack a tdb
61  */
62 static int ctdb_repack_tdb(struct tdb_context *tdb)
63 {
64         struct tdb_context *tmp_db;
65         struct vacuum_traverse_state state;
66
67         if (tdb_transaction_start(tdb) != 0) {
68                 DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction\n"));
69                 return -1;
70         }
71
72         tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb),
73                           TDB_INTERNAL|TDB_DISALLOW_NESTING,
74                           O_RDWR|O_CREAT, 0);
75         if (tmp_db == NULL) {
76                 DEBUG(DEBUG_ERR,(__location__ " Failed to create tmp_db\n"));
77                 tdb_transaction_cancel(tdb);
78                 return -1;
79         }
80
81         state.error = false;
82         state.dest_db = tmp_db;
83
84         if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) {
85                 DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying out\n"));
86                 tdb_transaction_cancel(tdb);
87                 tdb_close(tmp_db);
88                 return -1;              
89         }
90
91         if (state.error) {
92                 DEBUG(DEBUG_ERR,(__location__ " Error during traversal\n"));
93                 tdb_transaction_cancel(tdb);
94                 tdb_close(tmp_db);
95                 return -1;
96         }
97
98         if (tdb_wipe_all(tdb) != 0) {
99                 DEBUG(DEBUG_ERR,(__location__ " Failed to wipe database\n"));
100                 tdb_transaction_cancel(tdb);
101                 tdb_close(tmp_db);
102                 return -1;
103         }
104
105         state.error = false;
106         state.dest_db = tdb;
107
108         if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) {
109                 DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying back\n"));
110                 tdb_transaction_cancel(tdb);
111                 tdb_close(tmp_db);
112                 return -1;              
113         }
114
115         if (state.error) {
116                 DEBUG(DEBUG_ERR,(__location__ " Error during second traversal\n"));
117                 tdb_transaction_cancel(tdb);
118                 tdb_close(tmp_db);
119                 return -1;
120         }
121
122         tdb_close(tmp_db);
123
124         if (tdb_transaction_commit(tdb) != 0) {
125                 DEBUG(DEBUG_ERR,(__location__ " Failed to commit\n"));
126                 return -1;
127         }
128
129         return 0;
130 }
131
132
133 /* repack one database */
134 static int ctdb_repack_db(struct ctdb_context *ctdb, uint32_t db_id, 
135                           bool persistent, uint32_t repack_limit)
136 {
137         struct ctdb_db_context *ctdb_db;
138         const char *name;
139         int size;
140
141         if (ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, db_id, ctdb, &name) != 0) {
142                 DEBUG(DEBUG_ERR,(__location__ " Failed to get name of db 0x%x\n", db_id));
143                 return -1;
144         }
145
146         ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), name, persistent, 0);
147         if (ctdb_db == NULL) {
148                 DEBUG(DEBUG_ERR,(__location__ " Failed to attach to database '%s'\n", name));
149                 return -1;
150         }
151
152         size = tdb_freelist_size(ctdb_db->ltdb->tdb);
153         if (size == -1) {
154                 DEBUG(DEBUG_ERR,(__location__ " Failed to get freelist size for '%s'\n", name));
155                 return -1;
156         }
157
158         if (size <= repack_limit) {
159                 return 0;
160         }
161
162         printf("Repacking %s with %u freelist entries\n", name, size);
163
164         if (ctdb_repack_tdb(ctdb_db->ltdb->tdb) != 0) {
165                 DEBUG(DEBUG_ERR,(__location__ " Failed to repack '%s'\n", name));
166                 return -1;
167         }
168
169         return 0;
170 }
171
172
173 /*
174   repack all our databases
175  */
176 int ctdb_repack(struct ctdb_context *ctdb, int argc, const char **argv)
177 {
178         struct ctdb_dbid_map *dbmap=NULL;
179         int ret, i;
180         /* a reasonable default limit to prevent us using too much memory */
181         uint32_t repack_limit = 10000; 
182
183         if (argc > 0) {
184                 repack_limit = atoi(argv[0]);
185         }
186
187         ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &dbmap);
188         if (ret != 0) {
189                 DEBUG(DEBUG_ERR, ("Unable to get dbids from local node\n"));
190                 return ret;
191         }
192
193         for (i=0;i<dbmap->num;i++) {
194                 if (ctdb_repack_db(ctdb, dbmap->dbs[i].dbid, 
195                                    dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT, repack_limit) != 0) {
196                         DEBUG(DEBUG_ERR,("Failed to repack db 0x%x\n", dbmap->dbs[i].dbid));
197                         return -1;
198                 }
199         }
200
201         return 0;
202 }