]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/accurate.c
ebl try to cleanup hash driver
[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 John Walker.
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 typedef struct PrivateCurFile {
37 #ifndef USE_TCHDB
38    hlink link;
39 #endif
40    char *fname;                 /* not stored with tchdb mode */
41    time_t ctime;
42    time_t mtime;
43    bool seen;
44 } CurFile;
45
46 #ifdef USE_TCHDB
47
48 static bool accurate_mark_file_as_seen(JCR *jcr, CurFile *elt)
49 {
50    bool ret=true;
51
52    elt->seen = 1;
53    if (!tchdbputasync(jcr->file_list, 
54                       elt->fname, strlen(elt->fname)+1, 
55                       elt, sizeof(CurFile)))
56    {
57       Dmsg1(2, "can't update <%s>\n", elt->fname);
58       ret = false;              /* TODO: add error message */
59    }
60
61    return ret;
62 }
63
64 static bool accurate_lookup(JCR *jcr, char *fname, CurFile *ret)
65 {
66    bool found=false;
67    ret->seen = 0;
68
69    if (tchdbget3(jcr->file_list, 
70                  fname, strlen(fname)+1, 
71                  ret, sizeof(CurFile)) != -1)
72    {
73       found = true;
74       ret->fname = fname;
75    }
76
77    if (found) {
78       Dmsg1(2, "lookup <%s> ok\n", fname);
79    }
80
81    return found;
82 }
83
84 static bool accurate_init(JCR *jcr, int nbfile)
85 {
86    jcr->file_list = tchdbnew();
87    tchdbsetcache(jcr->file_list, 300000);
88    tchdbtune(jcr->file_list,
89              nbfile,            /* nb bucket 0.5n to 4n */
90              6,                 /* size of element 2^x */
91              16,
92              0);                /* options like compression */
93    /* TODO: make accurate file unique */
94    POOLMEM *name  = get_pool_memory(PM_MESSAGE);
95    make_unique_filename(name, jcr->JobId, "accurate");
96
97    if(!tchdbopen(jcr->file_list, name, HDBOWRITER | HDBOCREAT)){
98       /* TODO: handle error creation */
99       //ecode = tchdbecode(hdb);
100       //fprintf(stderr, "open error: %s\n", tchdberrmsg(ecode));
101    }
102    free_pool_memory(name);
103    return true;
104 }
105
106
107 bool accurate_send_deleted_list(JCR *jcr)
108 {
109    CurFile elt;
110    FF_PKT *ff_pkt;
111    int stream = STREAM_UNIX_ATTRIBUTES;
112
113    if (!jcr->accurate || jcr->JobLevel == L_FULL) {
114       goto bail_out;
115    }
116
117    if (jcr->file_list == NULL) {
118       goto bail_out;
119    }
120
121    ff_pkt = init_find_files();
122    ff_pkt->type = FT_DELETED;
123
124    char *key;
125   /* traverse records */
126    tchdbiterinit(jcr->file_list);
127    while((key = tchdbiternext2(jcr->file_list)) != NULL) {
128       if (tchdbget3(jcr->file_list, 
129                     key, strlen(key)+1, 
130                     &elt, sizeof(CurFile)) != -1)
131       {
132          if (!elt.seen) {
133             ff_pkt->fname = key;
134             ff_pkt->statp.st_mtime = elt.mtime;
135             ff_pkt->statp.st_ctime = elt.ctime;
136             encode_and_send_attributes(jcr, ff_pkt, stream);
137             Dmsg1(2, "deleted <%s>\n", key);
138          }
139 //         free(key);
140
141       } else {                  /* TODO: add error message */
142          Dmsg1(2, "No value for <%s> key\n", key);
143       }
144    }
145
146    term_find_files(ff_pkt);
147 bail_out:
148    /* TODO: clean htable when this function is not reached ? */
149    if (jcr->file_list) {
150       if(!tchdbclose(jcr->file_list)){
151 //       ecode = tchdbecode(hdb);
152 //       fprintf(stderr, "close error: %s\n", tchdberrmsg(ecode));
153       }
154
155       /* delete the object */
156       tchdbdel(jcr->file_list);
157
158       POOLMEM *name  = get_pool_memory(PM_MESSAGE);
159       make_unique_filename(name, jcr->JobId, "accurate");
160
161 //    unlink(name);
162
163       free_pool_memory(name);
164
165       jcr->file_list = NULL;
166    }
167    return true;
168 }
169
170 #else  /* HTABLE mode */
171
172 static bool accurate_mark_file_as_seen(JCR *jcr, CurFile *elt)
173 {
174    CurFile *temp = (CurFile *)jcr->file_list->lookup(elt->fname);
175    temp->seen = 1;              /* records are in memory */
176    return true;
177 }
178
179 static bool accurate_lookup(JCR *jcr, char *fname, CurFile *ret)
180 {
181    bool found=false;
182    ret->seen = 0;
183
184    CurFile *temp = (CurFile *)jcr->file_list->lookup(fname);
185    if (temp) {
186       memcpy(ret, temp, sizeof(CurFile));
187       found=true;
188    }
189
190    if (found) {
191       Dmsg1(2, "lookup <%s> ok\n", fname);
192    }
193
194    return found;
195 }
196
197 static bool accurate_init(JCR *jcr, int nbfile)
198 {
199    CurFile *elt=NULL;
200    jcr->file_list = (htable *)malloc(sizeof(htable));
201    jcr->file_list->init(elt, &elt->link, nbfile);
202    return true;
203 }
204
205 bool accurate_send_deleted_list(JCR *jcr)
206 {
207    CurFile *elt;
208    FF_PKT *ff_pkt;
209    int stream = STREAM_UNIX_ATTRIBUTES;
210
211    if (!jcr->accurate || jcr->JobLevel == L_FULL) {
212       goto bail_out;
213    }
214
215    if (jcr->file_list == NULL) {
216       goto bail_out;
217    }
218
219    ff_pkt = init_find_files();
220    ff_pkt->type = FT_DELETED;
221
222    foreach_htable (elt, jcr->file_list) {
223       if (!elt->seen) { /* already seen */
224          Dmsg2(1, "deleted fname=%s seen=%i\n", elt->fname, elt->seen);
225          ff_pkt->fname = elt->fname;
226          ff_pkt->statp.st_mtime = elt->mtime;
227          ff_pkt->statp.st_ctime = elt->ctime;
228          encode_and_send_attributes(jcr, ff_pkt, stream);
229       }
230 //      free(elt->fname);
231    }
232
233    term_find_files(ff_pkt);
234 bail_out:
235    /* TODO: clean htable when this function is not reached ? */
236    if (jcr->file_list) {
237       jcr->file_list->destroy();
238       free(jcr->file_list);
239       jcr->file_list = NULL;
240    }
241    return true;
242 }
243
244 #endif
245
246 static bool accurate_add_file(JCR *jcr, char *fname, char *lstat)
247 {
248    CurFile elt;
249    struct stat statp;
250    int LinkFIc;
251    decode_stat(lstat, &statp, &LinkFIc); /* decode catalog stat */
252    elt.ctime = statp.st_ctime;
253    elt.mtime = statp.st_mtime;
254    elt.seen = 0;
255
256 #ifdef USE_TCHDB
257    if (!tchdbputasync(jcr->file_list,
258                       fname, strlen(fname)+1,
259                       &elt, sizeof(CurFile)))
260    {
261       Dmsg1(2, "Can't add <%s> to file_list\n", fname);
262       /* TODO: check error */
263    }
264 #else  /* HTABLE */
265    CurFile *item;
266    /* we store CurFile, fname and ctime/mtime in the same chunk */
267    item = (CurFile *)jcr->file_list->hash_malloc(sizeof(CurFile)+strlen(fname)+1);
268    memcpy(item, &elt, sizeof(CurFile));
269    item->fname  = (char *)item+sizeof(CurFile);
270    strcpy(item->fname, fname);
271    jcr->file_list->insert(item->fname, item); 
272 #endif
273
274    Dmsg2(2, "add fname=<%s> lstat=%s\n", fname, lstat);
275    return true;
276 }
277
278 /*
279  * This function is called for each file seen in fileset.
280  * We check in file_list hash if fname have been backuped
281  * the last time. After we can compare Lstat field. 
282  * Full Lstat usage have been removed on 6612 
283  */
284 bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
285 {
286    bool stat = false;
287    char *fname;
288    CurFile elt;
289
290    if (!jcr->accurate || jcr->JobLevel == L_FULL) {
291       return true;
292    }
293
294    strip_path(ff_pkt);
295  
296    if (S_ISDIR(ff_pkt->statp.st_mode)) {
297       fname = ff_pkt->link;
298    } else {
299       fname = ff_pkt->fname;
300    } 
301
302    if (!accurate_lookup(jcr, fname, &elt)) {
303       Dmsg1(2, "accurate %s (not found)\n", fname);
304       stat = true;
305       goto bail_out;
306    }
307
308    if (elt.seen) { /* file has been seen ? */
309       Dmsg1(2, "accurate %s (already seen)\n", fname);
310       goto bail_out;
311    }
312
313    if (elt.mtime != ff_pkt->statp.st_mtime) {
314      Jmsg(jcr, M_SAVED, 0, _("%s      st_mtime differs\n"), fname);
315      stat = true;
316    } else if (elt.ctime != ff_pkt->statp.st_ctime) {
317      Jmsg(jcr, M_SAVED, 0, _("%s      st_ctime differs\n"), fname);
318      stat = true;
319    }
320
321    if (stat) {
322       Dmsg4(1, "%i = %i\t%i = %i\n", elt.mtime, ff_pkt->statp.st_mtime,
323             elt.ctime, ff_pkt->statp.st_ctime);
324    }
325
326    accurate_mark_file_as_seen(jcr, &elt);
327    Dmsg2(2, "accurate %s = %i\n", fname, stat);
328
329 bail_out:
330    unstrip_path(ff_pkt);
331    return stat;
332 }
333
334 /* 
335  * TODO: use bigbuffer from htable
336  */
337 int accurate_cmd(JCR *jcr)
338 {
339    BSOCK *dir = jcr->dir_bsock;
340    int len;
341    int32_t nb;
342
343    if (!jcr->accurate || job_canceled(jcr) || jcr->JobLevel==L_FULL) {
344       return true;
345    }
346
347    if (sscanf(dir->msg, "accurate files=%ld", &nb) != 1) {
348       dir->fsend(_("2991 Bad accurate command\n"));
349       return false;
350    }
351    Dmsg2(2, "nb=%d msg=%s\n", nb, dir->msg);
352
353    accurate_init(jcr, nb);
354
355    /*
356     * buffer = sizeof(CurFile) + dirmsg
357     * dirmsg = fname + \0 + lstat
358     */
359    /* get current files */
360    while (dir->recv() >= 0) {
361       Dmsg1(2, "accurate_cmd fname=%s\n", dir->msg);
362       len = strlen(dir->msg) + 1;
363       if (len < dir->msglen) {
364          accurate_add_file(jcr, dir->msg, dir->msg + len);
365       }
366    }
367
368 #ifdef DEBUG
369    extern void *start_heap;
370
371    char b1[50], b2[50], b3[50], b4[50], b5[50];
372    Dmsg5(1," Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n",
373          edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
374          edit_uint64_with_commas(sm_bytes, b2),
375          edit_uint64_with_commas(sm_max_bytes, b3),
376          edit_uint64_with_commas(sm_buffers, b4),
377          edit_uint64_with_commas(sm_max_buffers, b5));
378
379 #endif
380
381    return true;
382 }