auth/credentials: add cli_credentials_set_utf16_password()
[obnox/samba/samba-obnox.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 "lib/tdb_wrap/tdb_wrap.h"
27
28 /* should be tunable */
29 #define TIMELIMIT() timeval_current_ofs(10, 0)
30
31
32 struct vacuum_traverse_state {
33         bool error;
34         struct tdb_context *dest_db;
35 };
36
37 /*
38   traverse function for repacking
39  */
40 static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
41 {
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;
46         }
47         return 0;
48 }
49
50 /*
51   repack a tdb
52  */
53 static int ctdb_repack_tdb(struct tdb_context *tdb)
54 {
55         struct tdb_context *tmp_db;
56         struct vacuum_traverse_state state;
57
58         if (tdb_transaction_start(tdb) != 0) {
59                 DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction\n"));
60                 return -1;
61         }
62
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;
70         }
71
72         state.error = false;
73         state.dest_db = tmp_db;
74
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;              
80         }
81
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;
87         }
88
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;
94         }
95
96         state.error = false;
97         state.dest_db = tdb;
98
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;              
104         }
105
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;
111         }
112
113         tdb_close(tmp_db);
114
115         if (tdb_transaction_commit(tdb) != 0) {
116                 DEBUG(DEBUG_ERR,(__location__ " Failed to commit\n"));
117                 return -1;
118         }
119
120         return 0;
121 }
122
123
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)
127 {
128         struct ctdb_db_context *ctdb_db;
129         const char *name;
130         int size;
131
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;
135         }
136
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;
141         }
142
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;
147         }
148
149         if (size <= repack_limit) {
150                 return 0;
151         }
152
153         printf("Repacking %s with %u freelist entries\n", name, size);
154
155         if (ctdb_repack_tdb(ctdb_db->ltdb->tdb) != 0) {
156                 DEBUG(DEBUG_ERR,(__location__ " Failed to repack '%s'\n", name));
157                 return -1;
158         }
159
160         return 0;
161 }
162
163
164 /*
165   repack all our databases
166  */
167 int ctdb_repack(struct ctdb_context *ctdb, int argc, const char **argv)
168 {
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; 
173
174         if (argc > 0) {
175                 repack_limit = atoi(argv[0]);
176         }
177
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;
182         }
183
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;
189                 }
190         }
191
192         return 0;
193 }