The Machine Perception Toolbox

[Introduction]- [News]- [Download]- [Screenshots]- [Manual (pdf)]- [Forums]- [API Reference]- [Repository ]

 

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

hcache.c

Go to the documentation of this file.
00001 /*
00002  * This file has been donated to Jam.
00003  */
00004 
00005 # include "jam.h"
00006 # include "lists.h"
00007 # include "parse.h"
00008 # include "rules.h"
00009 # include "regexp.h"
00010 # include "headers.h"
00011 # include "newstr.h"
00012 # include "hash.h"
00013 # include "hcache.h"
00014 # include "variable.h"
00015 # include "search.h"
00016 
00017 #ifdef OPT_HEADER_CACHE_EXT
00018 
00019 /*
00020  * Craig W. McPheeters, Alias|Wavefront.
00021  *
00022  * hcache.c hcache.h - handle cacheing of #includes in source files
00023  *
00024  * Create a cache of files scanned for headers.  When starting jam,
00025  * look for the cache file and load it if present.  When finished the
00026  * binding phase, create a new header cache.  The cache contains
00027  * files, their timestamps and the header files found in their scan.
00028  * During the binding phase of jam, look in the header cache first for
00029  * the headers contained in a file.  If the cache is present and
00030  * valid, use its contents.  This results in dramatic speedups with
00031  * large projects (eg. 3min -> 1min startup for one project.)
00032  *
00033  * External routines:
00034  *    hcache_init() - read and parse the local .jamdeps file.
00035  *    hcache_done() - write a new .jamdeps file
00036  *    hcache() - return list of headers on target.  Use cache or do a scan.
00037  *    
00038  * The dependency file format is an ascii file with 1 line per target.
00039  * Each line has the following fields:
00040  * @boundname@ timestamp @file@ @file@ @file@ ... \n
00041  * */
00042 
00043 struct hcachedata {
00044     char                *boundname;
00045     time_t              time;
00046     LIST                *includes;
00047     LIST                *hdrscan; /* the HDRSCAN value for this target */
00048     int                 age;    /* if too old, we'll remove it from cache */
00049     struct hcachedata   *next;
00050 } ;
00051 
00052 typedef struct hcachedata HCACHEDATA ;
00053 
00054 
00055 static struct hash *hcachehash = 0;
00056 static HCACHEDATA  *hcachelist = 0; 
00057 
00058 static int queries = 0;
00059 static int hits = 0;
00060 
00061 #define CACHE_FILE_VERSION "version 4"
00062 #define CACHE_RECORD_HEADER "header"
00063 #define CACHE_RECORD_END "end"
00064 
00065 /*
00066  * Return the name of the header cache file.  May return NULL.
00067  *
00068  * The user sets this by setting the HCACHEFILE variable in a Jamfile.
00069  * We cache the result so the user can't change the cache file during
00070  * header scanning.
00071  */
00072 static char*
00073 cache_name(void)
00074 {
00075     static char* name = 0;
00076     if (!name) {
00077         LIST *hcachevar = var_get("HCACHEFILE");
00078 
00079         if (hcachevar) {
00080             TARGET *t = bindtarget( hcachevar->string );
00081 
00082             pushsettings( t->settings );
00083         /* Don't expect cache file to be generated, so pass 0
00084            as third argument to search. */
00085             t->boundname = search( t->name, &t->time, 0 );
00086             popsettings( t->settings );
00087 
00088             if (hcachevar) {
00089                 name = copystr(t->boundname);
00090             }
00091         }
00092     }
00093     return name;
00094 }
00095 
00096 /*
00097  * Return the maximum age a cache entry can have before it is purged
00098  * from the cache.
00099  */
00100 static int
00101 cache_maxage(void)
00102 {
00103     int age = 100;
00104     LIST *var = var_get("HCACHEMAXAGE");
00105 
00106     if (var) {
00107         age = atoi(var->string);
00108         if (age < 0)
00109             age = 0;
00110     }
00111 
00112     return age;
00113 }
00114 
00115 /*
00116  * Read a netstring.  The caveat is that the string can't contain
00117  * ASCII 0.  The returned value is as returned by newstr(), so it need
00118  * not be freed.
00119  */
00120 char*
00121 read_netstring(FILE* f)
00122 {
00123     unsigned long len;
00124     static char* buf = NULL;
00125     static unsigned long buf_len = 0;
00126 
00127     if (fscanf(f, " %9lu", &len) != 1)
00128         return NULL;
00129     if (fgetc(f) != (int)'\t')
00130         return NULL;
00131 
00132     if (len > 1024 * 64)
00133         return NULL;            /* sanity check */
00134 
00135     if (len > buf_len)
00136     {
00137         unsigned long new_len = buf_len * 2;
00138         if (new_len < len)
00139             new_len = len;
00140         buf = (char*)realloc(buf, new_len + 1);
00141         if (buf)
00142             buf_len = new_len;
00143     }
00144 
00145     if (!buf)
00146         return NULL;
00147 
00148     if (fread(buf, 1, len, f) != len)
00149         return NULL;
00150     if (fgetc(f) != (int)'\n')
00151         return NULL;
00152 
00153     buf[len] = 0;
00154     return newstr(buf);
00155 }
00156 
00157 /*
00158  * Write a netstring.
00159  */
00160 void
00161 write_netstring(FILE* f, const char* s)
00162 {
00163     if (!s)
00164         s = "";
00165     fprintf(f, "%lu\t%s\n", strlen(s), s);
00166 }
00167 
00168 void
00169 hcache_init()
00170 {
00171     HCACHEDATA  cachedata, *c;
00172     FILE        *f;
00173     char        *version;
00174     int         header_count = 0;
00175     char*       hcachename;
00176 
00177     hcachehash = hashinit (sizeof (HCACHEDATA), "hcache");
00178 
00179     if (! (hcachename = cache_name()))
00180         return;
00181 
00182     if (! (f = fopen (hcachename, "rb" )))
00183         return;
00184     
00185     version = read_netstring(f);
00186     if (!version || strcmp(version, CACHE_FILE_VERSION)) {
00187         fclose(f);
00188         return;
00189     }
00190 
00191     while (1)
00192     {
00193         char* record_type;
00194         char *time_str;
00195         char *age_str;
00196         char *includes_count_str;
00197         char *hdrscan_count_str;
00198         int i, count;
00199         LIST *l;
00200 
00201         record_type = read_netstring(f);
00202         if (!record_type) {
00203             fprintf(stderr, "invalid %s\n", hcachename);
00204             goto bail;
00205         }
00206         if (!strcmp(record_type, CACHE_RECORD_END)) {
00207             break;
00208         }
00209         if (strcmp(record_type, CACHE_RECORD_HEADER)) {
00210             fprintf(stderr, "invalid %s with record separator <%s>\n",
00211                     hcachename, record_type ? record_type : "<null>");
00212             goto bail;
00213         }
00214         
00215         c = &cachedata;
00216             
00217         c->boundname = read_netstring(f);
00218         time_str = read_netstring(f);
00219         age_str = read_netstring(f);
00220         includes_count_str = read_netstring(f);
00221         
00222         if (!c->boundname || !time_str || !age_str
00223             || !includes_count_str)
00224         {
00225             fprintf(stderr, "invalid %s\n", hcachename);
00226             goto bail;
00227         }
00228 
00229         c->time = atoi(time_str);
00230         c->age = atoi(age_str) + 1;
00231 
00232         count = atoi(includes_count_str);
00233         for (l = 0, i = 0; i < count; i++) {
00234             char* s = read_netstring(f);
00235             if (!s) {
00236                 fprintf(stderr, "invalid %s\n", hcachename);
00237                 goto bail;
00238             }
00239             l = list_new(l, s);
00240         }
00241         c->includes = l;
00242 
00243         hdrscan_count_str = read_netstring(f);
00244         if (!includes_count_str) {
00245             list_free(c->includes);
00246             fprintf(stderr, "invalid %s\n", hcachename);
00247             goto bail;
00248         }
00249 
00250         count = atoi(hdrscan_count_str);
00251         for (l = 0, i = 0; i < count; i++) {
00252             char* s = read_netstring(f);
00253             if (!s) {
00254                 fprintf(stderr, "invalid %s\n", hcachename);
00255                 goto bail;
00256             }
00257             l = list_new(l, s);
00258         }
00259         c->hdrscan = l;
00260 
00261         if (!hashenter(hcachehash, (HASHDATA **)&c)) {
00262             fprintf(stderr, "can't insert header cache item, bailing on %s\n",
00263                     hcachename);
00264             goto bail;
00265         }
00266 
00267         c->next = hcachelist;
00268         hcachelist = c;
00269 
00270         header_count++;
00271     }
00272 
00273     if (DEBUG_HEADER) {
00274         printf("hcache read from file %s\n", hcachename);
00275     }
00276     
00277  bail:
00278     fclose(f);
00279 }
00280 
00281 void
00282 hcache_done()
00283 {
00284     FILE        *f;
00285     HCACHEDATA  *c;
00286     int         header_count = 0;
00287     char*       hcachename;
00288     int         maxage;
00289     
00290     if (!hcachehash)
00291         return;
00292 
00293     if (! (hcachename = cache_name()))
00294         return;
00295 
00296     if (! (f = fopen (hcachename, "wb" )))
00297         return;
00298 
00299     maxage = cache_maxage();
00300 
00301     /* print out the version */
00302     write_netstring(f, CACHE_FILE_VERSION);
00303 
00304     c = hcachelist;
00305     for (c = hcachelist; c; c = c->next) {
00306         LIST    *l;
00307         char time_str[30];
00308         char age_str[30];
00309         char includes_count_str[30];
00310         char hdrscan_count_str[30];
00311 
00312         if (maxage == 0)
00313             c->age = 0;
00314         else if (c->age > maxage)
00315             continue;
00316 
00317         sprintf(includes_count_str, "%lu", list_length(c->includes));
00318         sprintf(hdrscan_count_str, "%lu", list_length(c->hdrscan));
00319         sprintf(time_str, "%lu", c->time);
00320         sprintf(age_str, "%lu", c->age);
00321 
00322         write_netstring(f, CACHE_RECORD_HEADER);
00323         write_netstring(f, c->boundname);
00324         write_netstring(f, time_str);
00325         write_netstring(f, age_str);
00326         write_netstring(f, includes_count_str);
00327         for (l = c->includes; l; l = list_next(l)) {
00328             write_netstring(f, l->string);
00329         }
00330         write_netstring(f, hdrscan_count_str);
00331         for (l = c->hdrscan; l; l = list_next(l)) {
00332             write_netstring(f, l->string);
00333         }
00334         fputs("\n", f);
00335         header_count++;
00336     }
00337     write_netstring(f, CACHE_RECORD_END);
00338 
00339     if (DEBUG_HEADER) {
00340         printf("hcache written to %s.   %d dependencies, %.0f%% hit rate\n",
00341                hcachename, header_count,
00342                queries ? 100.0 * hits / queries : 0);
00343     }
00344 
00345     fclose (f);
00346 }
00347 
00348 LIST *
00349 hcache (TARGET *t, int rec, regexp *re[], LIST *hdrscan)
00350 {
00351     HCACHEDATA  cachedata, *c = &cachedata;
00352     LIST        *l = 0;
00353 
00354     ++queries;
00355 
00356     c->boundname = t->boundname;
00357 
00358     if (hashcheck (hcachehash, (HASHDATA **) &c))
00359     {
00360         if (c->time == t->time)
00361         {
00362             LIST *l1 = hdrscan, *l2 = c->hdrscan;
00363             while (l1 && l2) {
00364                 if (l1->string != l2->string) {
00365                     l1 = NULL;
00366                 } else {
00367                     l1 = list_next(l1);
00368                     l2 = list_next(l2);
00369                 }
00370             }
00371             if (l1 || l2) {
00372                 if (DEBUG_HEADER)
00373                     printf("HDRSCAN out of date in cache for %s\n",
00374                            t->boundname);
00375 
00376                 printf("HDRSCAN out of date for %s\n", t->boundname);
00377                 printf(" real  : ");
00378                 list_print(hdrscan);
00379                 printf("\n cached: ");
00380                 list_print(c->hdrscan);
00381                 printf("\n");
00382 
00383                 list_free(c->includes);
00384                 list_free(c->hdrscan);
00385                 c->includes = 0;
00386                 c->hdrscan = 0;
00387             } else {
00388                 if (DEBUG_HEADER)
00389                     printf ("using header cache for %s\n", t->boundname);
00390                 c->age = 0;
00391                 ++hits;
00392                 l = list_copy (0, c->includes);
00393                 return l;
00394             }
00395         } else {
00396             if (DEBUG_HEADER)
00397                 printf ("header cache out of date for %s\n", t->boundname);
00398             list_free (c->includes);
00399             list_free(c->hdrscan);
00400             c->includes = 0;
00401             c->hdrscan = 0;
00402         }
00403     } else {
00404         if (hashenter (hcachehash, (HASHDATA **)&c)) {
00405             c->boundname = newstr (c->boundname);
00406             c->next = hcachelist;
00407             hcachelist = c;
00408         }
00409     }
00410 
00411     /* 'c' points at the cache entry.  Its out of date. */
00412 
00413     l = headers1 (0, t->boundname, rec, re);
00414 
00415     c->time = t->time;
00416     c->age = 0;
00417     c->includes = list_copy (0, l);
00418     c->hdrscan = list_copy(0, hdrscan);
00419 
00420     return l;
00421 }
00422 
00423 #endif

Generated on Mon Nov 8 17:07:35 2004 for MPT by  doxygen 1.3.9.1