Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/tools/build/jam_src/hcache.c @ 12

Last change on this file since 12 was 12, checked in by landauf, 18 years ago

added boost

File size: 9.0 KB
Line 
1/*
2 * This file has been donated to Jam.
3 */
4
5# include "jam.h"
6# include "lists.h"
7# include "parse.h"
8# include "rules.h"
9# include "regexp.h"
10# include "headers.h"
11# include "newstr.h"
12# include "hash.h"
13# include "hcache.h"
14# include "variable.h"
15# include "search.h"
16
17#ifdef OPT_HEADER_CACHE_EXT
18
19/*
20 * Craig W. McPheeters, Alias|Wavefront.
21 *
22 * hcache.c hcache.h - handle cacheing of #includes in source files
23 *
24 * Create a cache of files scanned for headers.  When starting jam,
25 * look for the cache file and load it if present.  When finished the
26 * binding phase, create a new header cache.  The cache contains
27 * files, their timestamps and the header files found in their scan.
28 * During the binding phase of jam, look in the header cache first for
29 * the headers contained in a file.  If the cache is present and
30 * valid, use its contents.  This results in dramatic speedups with
31 * large projects (eg. 3min -> 1min startup for one project.)
32 *
33 * External routines:
34 *    hcache_init() - read and parse the local .jamdeps file.
35 *    hcache_done() - write a new .jamdeps file
36 *    hcache() - return list of headers on target.  Use cache or do a scan.
37 *   
38 * The dependency file format is an ascii file with 1 line per target.
39 * Each line has the following fields:
40 * @boundname@ timestamp @file@ @file@ @file@ ... \n
41 * */
42
43struct hcachedata {
44    char                *boundname;
45    time_t              time;
46    LIST                *includes;
47    LIST                *hdrscan; /* the HDRSCAN value for this target */
48    int                 age;    /* if too old, we'll remove it from cache */
49    struct hcachedata   *next;
50} ;
51
52typedef struct hcachedata HCACHEDATA ;
53
54
55static struct hash *hcachehash = 0;
56static HCACHEDATA  *hcachelist = 0; 
57
58static int queries = 0;
59static int hits = 0;
60
61#define CACHE_FILE_VERSION "version 4"
62#define CACHE_RECORD_HEADER "header"
63#define CACHE_RECORD_END "end"
64
65/*
66 * Return the name of the header cache file.  May return NULL.
67 *
68 * The user sets this by setting the HCACHEFILE variable in a Jamfile.
69 * We cache the result so the user can't change the cache file during
70 * header scanning.
71 */
72static char*
73cache_name(void)
74{
75    static char* name = 0;
76    if (!name) {
77        LIST *hcachevar = var_get("HCACHEFILE");
78
79        if (hcachevar) {
80            TARGET *t = bindtarget( hcachevar->string );
81
82            pushsettings( t->settings );
83        /* Don't expect cache file to be generated, so pass 0
84           as third argument to search. */
85            t->boundname = search( t->name, &t->time, 0 );
86            popsettings( t->settings );
87
88            if (hcachevar) {
89                name = copystr(t->boundname);
90            }
91        }
92    }
93    return name;
94}
95
96/*
97 * Return the maximum age a cache entry can have before it is purged
98 * from the cache.
99 */
100static int
101cache_maxage(void)
102{
103    int age = 100;
104    LIST *var = var_get("HCACHEMAXAGE");
105
106    if (var) {
107        age = atoi(var->string);
108        if (age < 0)
109            age = 0;
110    }
111
112    return age;
113}
114
115/*
116 * Read a netstring.  The caveat is that the string can't contain
117 * ASCII 0.  The returned value is as returned by newstr(), so it need
118 * not be freed.
119 */
120char*
121read_netstring(FILE* f)
122{
123    unsigned long len;
124    static char* buf = NULL;
125    static unsigned long buf_len = 0;
126
127    if (fscanf(f, " %9lu", &len) != 1)
128        return NULL;
129    if (fgetc(f) != (int)'\t')
130        return NULL;
131
132    if (len > 1024 * 64)
133        return NULL;            /* sanity check */
134
135    if (len > buf_len)
136    {
137        unsigned long new_len = buf_len * 2;
138        if (new_len < len)
139            new_len = len;
140        buf = (char*)realloc(buf, new_len + 1);
141        if (buf)
142            buf_len = new_len;
143    }
144
145    if (!buf)
146        return NULL;
147
148    if (fread(buf, 1, len, f) != len)
149        return NULL;
150    if (fgetc(f) != (int)'\n')
151        return NULL;
152
153    buf[len] = 0;
154    return newstr(buf);
155}
156
157/*
158 * Write a netstring.
159 */
160void
161write_netstring(FILE* f, const char* s)
162{
163    if (!s)
164        s = "";
165    fprintf(f, "%lu\t%s\n", strlen(s), s);
166}
167
168void
169hcache_init()
170{
171    HCACHEDATA  cachedata, *c;
172    FILE        *f;
173    char        *version;
174    int         header_count = 0;
175    char*       hcachename;
176
177    hcachehash = hashinit (sizeof (HCACHEDATA), "hcache");
178
179    if (! (hcachename = cache_name()))
180        return;
181
182    if (! (f = fopen (hcachename, "rb" )))
183        return;
184   
185    version = read_netstring(f);
186    if (!version || strcmp(version, CACHE_FILE_VERSION)) {
187        fclose(f);
188        return;
189    }
190
191    while (1)
192    {
193        char* record_type;
194        char *time_str;
195        char *age_str;
196        char *includes_count_str;
197        char *hdrscan_count_str;
198        int i, count;
199        LIST *l;
200
201        record_type = read_netstring(f);
202        if (!record_type) {
203            fprintf(stderr, "invalid %s\n", hcachename);
204            goto bail;
205        }
206        if (!strcmp(record_type, CACHE_RECORD_END)) {
207            break;
208        }
209        if (strcmp(record_type, CACHE_RECORD_HEADER)) {
210            fprintf(stderr, "invalid %s with record separator <%s>\n",
211                    hcachename, record_type ? record_type : "<null>");
212            goto bail;
213        }
214       
215        c = &cachedata;
216           
217        c->boundname = read_netstring(f);
218        time_str = read_netstring(f);
219        age_str = read_netstring(f);
220        includes_count_str = read_netstring(f);
221       
222        if (!c->boundname || !time_str || !age_str
223            || !includes_count_str)
224        {
225            fprintf(stderr, "invalid %s\n", hcachename);
226            goto bail;
227        }
228
229        c->time = atoi(time_str);
230        c->age = atoi(age_str) + 1;
231
232        count = atoi(includes_count_str);
233        for (l = 0, i = 0; i < count; i++) {
234            char* s = read_netstring(f);
235            if (!s) {
236                fprintf(stderr, "invalid %s\n", hcachename);
237                goto bail;
238            }
239            l = list_new(l, s);
240        }
241        c->includes = l;
242
243        hdrscan_count_str = read_netstring(f);
244        if (!includes_count_str) {
245            list_free(c->includes);
246            fprintf(stderr, "invalid %s\n", hcachename);
247            goto bail;
248        }
249
250        count = atoi(hdrscan_count_str);
251        for (l = 0, i = 0; i < count; i++) {
252            char* s = read_netstring(f);
253            if (!s) {
254                fprintf(stderr, "invalid %s\n", hcachename);
255                goto bail;
256            }
257            l = list_new(l, s);
258        }
259        c->hdrscan = l;
260
261        if (!hashenter(hcachehash, (HASHDATA **)&c)) {
262            fprintf(stderr, "can't insert header cache item, bailing on %s\n",
263                    hcachename);
264            goto bail;
265        }
266
267        c->next = hcachelist;
268        hcachelist = c;
269
270        header_count++;
271    }
272
273    if (DEBUG_HEADER) {
274        printf("hcache read from file %s\n", hcachename);
275    }
276   
277 bail:
278    fclose(f);
279}
280
281void
282hcache_done()
283{
284    FILE        *f;
285    HCACHEDATA  *c;
286    int         header_count = 0;
287    char*       hcachename;
288    int         maxage;
289   
290    if (!hcachehash)
291        return;
292
293    if (! (hcachename = cache_name()))
294        return;
295
296    if (! (f = fopen (hcachename, "wb" )))
297        return;
298
299    maxage = cache_maxage();
300
301    /* print out the version */
302    write_netstring(f, CACHE_FILE_VERSION);
303
304    c = hcachelist;
305    for (c = hcachelist; c; c = c->next) {
306        LIST    *l;
307        char time_str[30];
308        char age_str[30];
309        char includes_count_str[30];
310        char hdrscan_count_str[30];
311
312        if (maxage == 0)
313            c->age = 0;
314        else if (c->age > maxage)
315            continue;
316
317        sprintf(includes_count_str, "%lu", list_length(c->includes));
318        sprintf(hdrscan_count_str, "%lu", list_length(c->hdrscan));
319        sprintf(time_str, "%lu", c->time);
320        sprintf(age_str, "%lu", c->age);
321
322        write_netstring(f, CACHE_RECORD_HEADER);
323        write_netstring(f, c->boundname);
324        write_netstring(f, time_str);
325        write_netstring(f, age_str);
326        write_netstring(f, includes_count_str);
327        for (l = c->includes; l; l = list_next(l)) {
328            write_netstring(f, l->string);
329        }
330        write_netstring(f, hdrscan_count_str);
331        for (l = c->hdrscan; l; l = list_next(l)) {
332            write_netstring(f, l->string);
333        }
334        fputs("\n", f);
335        header_count++;
336    }
337    write_netstring(f, CACHE_RECORD_END);
338
339    if (DEBUG_HEADER) {
340        printf("hcache written to %s.   %d dependencies, %.0f%% hit rate\n",
341               hcachename, header_count,
342               queries ? 100.0 * hits / queries : 0);
343    }
344
345    fclose (f);
346}
347
348LIST *
349hcache (TARGET *t, int rec, regexp *re[], LIST *hdrscan)
350{
351    HCACHEDATA  cachedata, *c = &cachedata;
352    LIST        *l = 0;
353
354    ++queries;
355
356    c->boundname = t->boundname;
357
358    if (hashcheck (hcachehash, (HASHDATA **) &c))
359    {
360        if (c->time == t->time)
361        {
362            LIST *l1 = hdrscan, *l2 = c->hdrscan;
363            while (l1 && l2) {
364                if (l1->string != l2->string) {
365                    l1 = NULL;
366                } else {
367                    l1 = list_next(l1);
368                    l2 = list_next(l2);
369                }
370            }
371            if (l1 || l2) {
372                if (DEBUG_HEADER)
373                    printf("HDRSCAN out of date in cache for %s\n",
374                           t->boundname);
375
376                printf("HDRSCAN out of date for %s\n", t->boundname);
377                printf(" real  : ");
378                list_print(hdrscan);
379                printf("\n cached: ");
380                list_print(c->hdrscan);
381                printf("\n");
382
383                list_free(c->includes);
384                list_free(c->hdrscan);
385                c->includes = 0;
386                c->hdrscan = 0;
387            } else {
388                if (DEBUG_HEADER)
389                    printf ("using header cache for %s\n", t->boundname);
390                c->age = 0;
391                ++hits;
392                l = list_copy (0, c->includes);
393                return l;
394            }
395        } else {
396            if (DEBUG_HEADER)
397                printf ("header cache out of date for %s\n", t->boundname);
398            list_free (c->includes);
399            list_free(c->hdrscan);
400            c->includes = 0;
401            c->hdrscan = 0;
402        }
403    } else {
404        if (hashenter (hcachehash, (HASHDATA **)&c)) {
405            c->boundname = newstr (c->boundname);
406            c->next = hcachelist;
407            hcachelist = c;
408        }
409    }
410
411    /* 'c' points at the cache entry.  Its out of date. */
412
413    l = headers1 (0, t->boundname, rec, re);
414
415    c->time = t->time;
416    c->age = 0;
417    c->includes = list_copy (0, l);
418    c->hdrscan = list_copy(0, hdrscan);
419
420    return l;
421}
422
423#endif
Note: See TracBrowser for help on using the repository browser.