]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/accurate.c
Fix bad debug code call in src/filed/accurate.c
[bacula/bacula] / bacula / src / filed / accurate.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *  Version $Id $
30  *
31  */
32
33 #include "bacula.h"
34 #include "filed.h"
35
36 static int dbglvl=200;
37
38 typedef struct PrivateCurFile {
39 #ifndef USE_TCADB
40    hlink link;
41 #endif
42    char *fname;                 /* not stored with tchdb mode */
43    time_t ctime;
44    time_t mtime;
45    bool seen;
46 } CurFile;
47
48 #ifdef USE_TCADB
49 static void realfree(void *p);  /* used by tokyo code */
50
51 /*
52  * Update hash element seen=1
53  */
54 static bool accurate_mark_file_as_seen(JCR *jcr, CurFile *elt)
55 {
56    bool ret=true;
57
58    elt->seen = 1;
59    if (!tcadbput(jcr->file_list, 
60                  elt->fname, strlen(elt->fname)+1, 
61                  elt, sizeof(CurFile)))
62    { /* TODO: disabling accurate mode ?  */
63       Jmsg(jcr, M_ERROR, 1, _("Can't update accurate hash disk\n"));
64       ret = false;
65    }
66
67    return ret;
68 }
69
70 static bool accurate_lookup(JCR *jcr, char *fname, CurFile *ret)
71 {
72    bool found=false;
73    ret->seen = 0;
74    int size;
75    CurFile *elt;
76
77    elt = (CurFile*)tcadbget(jcr->file_list, 
78                             fname, strlen(fname)+1, &size);
79    if (elt)
80    {
81       /* TODO: don't malloc/free results */
82       found = true;
83       elt->fname = fname;
84       memcpy(ret, elt, sizeof(CurFile));
85       realfree(elt);
86 //    Dmsg1(dbglvl, "lookup <%s> ok\n", fname);
87    }
88    return found;
89 }
90
91 /* Create tokyo dbm hash file 
92  * If something goes wrong, we cancel accurate mode.
93  */
94 static bool accurate_init(JCR *jcr, int nbfile)
95 {
96    jcr->file_list = tcadbnew();
97 //
98 //   tchdbsetcache(jcr->file_list, 300000);
99 //   tchdbtune(jcr->file_list,
100 //           nbfile,            /* nb bucket 0.5n to 4n */
101 //           6,                 /* size of element 2^x */
102 //           16,
103 //           0);                /* options like compression */
104 //
105    jcr->hash_name  = get_pool_memory(PM_MESSAGE);
106    POOLMEM *temp = get_pool_memory(PM_MESSAGE);
107
108    if (nbfile > 500000) {
109       make_unique_filename(&jcr->hash_name, jcr->JobId, "accurate");
110       pm_strcat(jcr->hash_name, ".tcb");
111       Mmsg(temp, "%s#bnum=%i#mode=e#opts=l",
112            jcr->hash_name, nbfile*4); 
113       Dmsg1(dbglvl, "Doing accurate hash on disk %s\n", jcr->hash_name);
114    } else {
115       Dmsg0(dbglvl, "Doing accurate hash on memory\n");
116       pm_strcpy(jcr->hash_name, "*");
117       pm_strcpy(temp, "*");
118    }
119    
120    if(!tcadbopen(jcr->file_list, jcr->hash_name)){
121       Jmsg(jcr, M_ERROR, 1, _("Can't open accurate hash disk\n"));
122       Jmsg(jcr, M_INFO, 1, _("Disabling accurate mode\n"));
123       tcadbdel(jcr->file_list);
124       jcr->file_list = NULL;
125       jcr->accurate = false;
126    }
127    free_pool_memory(temp);
128    return jcr->file_list != NULL;
129 }
130
131 /* This function is called at the end of backup
132  * We walk over all hash disk element, and we check
133  * for elt.seen.
134  */
135 bool accurate_send_deleted_list(JCR *jcr)
136 {
137    char *key;
138    CurFile *elt;
139    int size;
140    FF_PKT *ff_pkt;
141    int stream = STREAM_UNIX_ATTRIBUTES;
142
143    if (!jcr->accurate || jcr->get_JobLevel() == L_FULL) {
144       goto bail_out;
145    }
146
147    if (jcr->file_list == NULL) {
148       goto bail_out;
149    }
150
151    ff_pkt = init_find_files();
152    ff_pkt->type = FT_DELETED;
153
154    /* traverse records */
155    tcadbiterinit(jcr->file_list);
156    while((key = tcadbiternext2(jcr->file_list)) != NULL) {
157       elt = (CurFile *) tcadbget(jcr->file_list, 
158                                  key, strlen(key)+1, &size);
159       if (elt)
160       {
161          if (!elt->seen) {      /* already seen */
162             ff_pkt->fname = key;
163             ff_pkt->statp.st_mtime = elt->mtime;
164             ff_pkt->statp.st_ctime = elt->ctime;
165             encode_and_send_attributes(jcr, ff_pkt, stream);
166          }
167          realfree(elt);
168       }
169       realfree(key);            /* tokyo cabinet have to use real free() */
170    }
171
172    term_find_files(ff_pkt);
173 bail_out:
174    /* TODO: clean htable when this function is not reached ? */
175    if (jcr->file_list) {
176       if(!tcadbclose(jcr->file_list)){
177          Jmsg(jcr, M_ERROR, 1, _("Can't close accurate hash disk\n"));
178       }
179
180       /* delete the object */
181       tcadbdel(jcr->file_list);
182       if (!bstrcmp(jcr->hash_name, "*")) {
183          unlink(jcr->hash_name);
184       }
185
186       free_pool_memory(jcr->hash_name);
187       jcr->hash_name = NULL;
188       jcr->file_list = NULL;
189    }
190    return true;
191 }
192
193 #else  /* HTABLE mode */
194
195 static bool accurate_mark_file_as_seen(JCR *jcr, CurFile *elt)
196 {
197    CurFile *temp = (CurFile *)jcr->file_list->lookup(elt->fname);
198    temp->seen = 1;              /* records are in memory */
199    return true;
200 }
201
202 static bool accurate_lookup(JCR *jcr, char *fname, CurFile *ret)
203 {
204    bool found=false;
205    ret->seen = 0;
206
207    CurFile *temp = (CurFile *)jcr->file_list->lookup(fname);
208    if (temp) {
209       memcpy(ret, temp, sizeof(CurFile));
210       found=true;
211 //    Dmsg1(dbglvl, "lookup <%s> ok\n", fname);
212    }
213
214    return found;
215 }
216
217 static bool accurate_init(JCR *jcr, int nbfile)
218 {
219    CurFile *elt = NULL;
220    jcr->file_list = (htable *)malloc(sizeof(htable));
221    jcr->file_list->init(elt, &elt->link, nbfile);
222    return true;
223 }
224
225 /* This function is called at the end of backup
226  * We walk over all hash disk element, and we check
227  * for elt.seen.
228  */
229 bool accurate_send_deleted_list(JCR *jcr)
230 {
231    CurFile *elt;
232    FF_PKT *ff_pkt;
233    int stream = STREAM_UNIX_ATTRIBUTES;
234
235    if (!jcr->accurate || jcr->get_JobLevel() == L_FULL) {
236       goto bail_out;
237    }
238
239    if (jcr->file_list == NULL) {
240       goto bail_out;
241    }
242
243    ff_pkt = init_find_files();
244    ff_pkt->type = FT_DELETED;
245
246    foreach_htable(elt, jcr->file_list) {
247       if (!elt->seen) { /* already seen */
248          Dmsg2(dbglvl, "deleted fname=%s seen=%i\n", elt->fname, elt->seen);
249          ff_pkt->fname = elt->fname;
250          ff_pkt->statp.st_mtime = elt->mtime;
251          ff_pkt->statp.st_ctime = elt->ctime;
252          encode_and_send_attributes(jcr, ff_pkt, stream);
253       }
254 //      free(elt->fname);
255    }
256
257    term_find_files(ff_pkt);
258 bail_out:
259    /* TODO: clean htable when this function is not reached ? */
260    if (jcr->file_list) {
261       jcr->file_list->destroy();
262       free(jcr->file_list);
263       jcr->file_list = NULL;
264    }
265    return true;
266 }
267
268 #endif /* common code */
269
270 static bool accurate_add_file(JCR *jcr, char *fname, char *lstat)
271 {
272    bool ret = true;
273    CurFile elt;
274    struct stat statp;
275    int LinkFIc;
276    decode_stat(lstat, &statp, &LinkFIc); /* decode catalog stat */
277    elt.ctime = statp.st_ctime;
278    elt.mtime = statp.st_mtime;
279    elt.seen = 0;
280
281 #ifdef USE_TCADB
282    if (!tcadbput(jcr->file_list,
283                  fname, strlen(fname)+1,
284                  &elt, sizeof(CurFile)))
285    {
286       Jmsg(jcr, M_ERROR, 1, _("Can't update accurate hash disk ERR=%s\n"));
287       ret = false;
288    }
289 #else  /* HTABLE */
290    CurFile *item;
291    /* we store CurFile, fname and ctime/mtime in the same chunk */
292    item = (CurFile *)jcr->file_list->hash_malloc(sizeof(CurFile)+strlen(fname)+1);
293    memcpy(item, &elt, sizeof(CurFile));
294    item->fname  = (char *)item+sizeof(CurFile);
295    strcpy(item->fname, fname);
296    jcr->file_list->insert(item->fname, item); 
297 #endif
298
299 // Dmsg2(dbglvl, "add fname=<%s> lstat=%s\n", fname, lstat);
300    return ret;
301 }
302
303 /*
304  * This function is called for each file seen in fileset.
305  * We check in file_list hash if fname have been backuped
306  * the last time. After we can compare Lstat field. 
307  * Full Lstat usage have been removed on 6612 
308  */
309 bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
310 {
311    bool stat = false;
312    char *fname;
313    CurFile elt;
314
315    if (!jcr->accurate || jcr->get_JobLevel() == L_FULL) {
316       return true;
317    }
318
319    strip_path(ff_pkt);
320  
321    if (S_ISDIR(ff_pkt->statp.st_mode)) {
322       fname = ff_pkt->link;
323    } else {
324       fname = ff_pkt->fname;
325    } 
326
327    if (!accurate_lookup(jcr, fname, &elt)) {
328       Dmsg1(dbglvl, "accurate %s (not found)\n", fname);
329       stat = true;
330       goto bail_out;
331    }
332
333    if (elt.seen) { /* file has been seen ? */
334       Dmsg1(dbglvl, "accurate %s (already seen)\n", fname);
335       goto bail_out;
336    }
337
338    if (elt.mtime != ff_pkt->statp.st_mtime) {
339 //   Jmsg(jcr, M_SAVED, 0, _("%s      st_mtime differs\n"), fname);
340      Dmsg1(dbglvl, "%s      st_mtime differs\n", fname);
341      stat = true;
342    } else if (elt.ctime != ff_pkt->statp.st_ctime) {
343 //   Jmsg(jcr, M_SAVED, 0, _("%s      st_ctime differs\n"), fname);
344      Dmsg1(dbglvl, "%s      st_ctime differs\n", fname);
345      stat = true;
346    }
347
348    accurate_mark_file_as_seen(jcr, &elt);
349    Dmsg2(dbglvl, "accurate %s = %i\n", fname, stat);
350
351 bail_out:
352    unstrip_path(ff_pkt);
353    return stat;
354 }
355
356 /* 
357  * TODO: use big buffer from htable
358  */
359 int accurate_cmd(JCR *jcr)
360 {
361    BSOCK *dir = jcr->dir_bsock;
362    int len;
363    int32_t nb;
364
365    if (!jcr->accurate || job_canceled(jcr) || jcr->get_JobLevel()==L_FULL) {
366       return true;
367    }
368
369    if (sscanf(dir->msg, "accurate files=%ld", &nb) != 1) {
370       dir->fsend(_("2991 Bad accurate command\n"));
371       return false;
372    }
373
374    accurate_init(jcr, nb);
375
376    /*
377     * buffer = sizeof(CurFile) + dirmsg
378     * dirmsg = fname + \0 + lstat
379     */
380    /* get current files */
381    while (dir->recv() >= 0) {
382       len = strlen(dir->msg) + 1;
383       if (len < dir->msglen) {
384          accurate_add_file(jcr, dir->msg, dir->msg + len);
385       }
386    }
387
388 #ifdef DEBUG
389    extern void *start_heap;
390
391    char b1[50], b2[50], b3[50], b4[50], b5[50];
392    Dmsg5(dbglvl," Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n",
393          edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
394          edit_uint64_with_commas(sm_bytes, b2),
395          edit_uint64_with_commas(sm_max_bytes, b3),
396          edit_uint64_with_commas(sm_buffers, b4),
397          edit_uint64_with_commas(sm_max_buffers, b5));
398 #endif
399
400    return true;
401 }
402
403 #ifdef USE_TCADB
404
405 /*
406  * Tokyo Cabinet library doesn't use smartalloc by default
407  * results need to be released with real free()
408  */
409 #undef free
410 void realfree(void *p)
411 {
412    free(p);
413 }
414
415 #endif