]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/engine/hcache.cpp
2 * This file has been donated to Jam.
6 * Craig W. McPheeters, Alias|Wavefront.
8 * hcache.c hcache.h - handle caching of #includes in source files.
10 * Create a cache of files scanned for headers. When starting jam, look for the
11 * cache file and load it if present. When finished the binding phase, create a
12 * new header cache. The cache contains files, their timestamps and the header
13 * files found in their scan. During the binding phase of jam, look in the
14 * header cache first for the headers contained in a file. If the cache is
15 * present and valid, use its contents. This results in dramatic speedups with
16 * large projects (e.g. 3min -> 1min startup for one project.)
19 * hcache_init() - read and parse the local .jamdeps file.
20 * hcache_done() - write a new .jamdeps file.
21 * hcache() - return list of headers on target. Use cache or do a scan.
23 * The dependency file format is an ASCII file with 1 line per target. Each line
24 * has the following fields:
25 * @boundname@ timestamp_sec timestamp_nsec @file@ @file@ @file@ ...
30 #ifdef OPT_HEADER_CACHE_EXT
44 #include "timestamp.h"
51 typedef struct hcachedata HCACHEDATA
;
58 LIST
* hdrscan
; /* the HDRSCAN value for this target */
59 int age
; /* if too old, we will remove it from cache */
64 static struct hash
* hcachehash
= 0;
65 static HCACHEDATA
* hcachelist
= 0;
67 static int queries
= 0;
70 #define CACHE_FILE_VERSION "version 5"
71 #define CACHE_RECORD_HEADER "header"
72 #define CACHE_RECORD_END "end"
76 * Return the name of the header cache file. May return NULL.
78 * The user sets this by setting the HCACHEFILE variable in a Jamfile. We cache
79 * the result so the user can not change the cache file during header scanning.
82 static const char * cache_name( void )
84 static OBJECT
* name
= 0;
87 LIST
* const hcachevar
= var_get( root_module(), constant_HCACHEFILE
);
89 if ( !list_empty( hcachevar
) )
91 TARGET
* const t
= bindtarget( list_front( hcachevar
) );
93 pushsettings( root_module(), t
->settings
);
94 /* Do not expect the cache file to be generated, so pass 0 as the
95 * third argument to search. Expect the location to be specified via
96 * LOCATE, so pass 0 as the fourth argument.
98 object_free( t
->boundname
);
99 t
->boundname
= search( t
->name
, &t
->time
, 0, 0 );
100 popsettings( root_module(), t
->settings
);
102 name
= object_copy( t
->boundname
);
105 return name
? object_str( name
) : 0;
110 * Return the maximum age a cache entry can have before it is purged from the
114 static int cache_maxage( void )
117 LIST
* const var
= var_get( root_module(), constant_HCACHEMAXAGE
);
118 if ( !list_empty( var
) )
120 age
= atoi( object_str( list_front( var
) ) );
129 * Read a netstring. The caveat is that the string can not contain ASCII 0. The
130 * returned value is as returned by object_new().
133 OBJECT
* read_netstring( FILE * f
)
136 static char * buf
= NULL
;
137 static unsigned long buf_len
= 0;
139 if ( fscanf( f
, " %9lu", &len
) != 1 )
141 if ( fgetc( f
) != (int)'\t' )
144 if ( len
> 1024 * 64 )
145 return NULL
; /* sanity check */
149 unsigned long new_len
= buf_len
* 2;
152 buf
= (char *)BJAM_REALLOC( buf
, new_len
+ 1 );
160 if ( fread( buf
, 1, len
, f
) != len
)
162 if ( fgetc( f
) != (int)'\n' )
166 return object_new( buf
);
174 void write_netstring( FILE * f
, char const * s
)
178 fprintf( f
, "%lu\t%s\n", (long unsigned)strlen( s
), s
);
185 OBJECT
* version
= 0;
186 int header_count
= 0;
187 const char * hcachename
;
192 hcachehash
= hashinit( sizeof( HCACHEDATA
), "hcache" );
194 if ( !( hcachename
= cache_name() ) )
197 if ( !( f
= fopen( hcachename
, "rb" ) ) )
199 if ( errno
!= ENOENT
)
200 err_printf( "[errno %d] failed to read hcache file '%s': %s",
201 errno
, hcachename
, strerror(errno
) );
205 version
= read_netstring( f
);
207 if ( !version
|| strcmp( object_str( version
), CACHE_FILE_VERSION
) )
212 HCACHEDATA cachedata
;
214 OBJECT
* record_type
= 0;
215 OBJECT
* time_secs_str
= 0;
216 OBJECT
* time_nsecs_str
= 0;
217 OBJECT
* age_str
= 0;
218 OBJECT
* includes_count_str
= 0;
219 OBJECT
* hdrscan_count_str
= 0;
225 cachedata
.boundname
= 0;
226 cachedata
.includes
= 0;
227 cachedata
.hdrscan
= 0;
229 record_type
= read_netstring( f
);
232 err_printf( "invalid %s\n", hcachename
);
235 if ( !strcmp( object_str( record_type
), CACHE_RECORD_END
) )
237 object_free( record_type
);
240 if ( strcmp( object_str( record_type
), CACHE_RECORD_HEADER
) )
242 err_printf( "invalid %s with record separator <%s>\n",
243 hcachename
, record_type
? object_str( record_type
) : "<null>" );
247 cachedata
.boundname
= read_netstring( f
);
248 time_secs_str
= read_netstring( f
);
249 time_nsecs_str
= read_netstring( f
);
250 age_str
= read_netstring( f
);
251 includes_count_str
= read_netstring( f
);
253 if ( !cachedata
.boundname
|| !time_secs_str
|| !time_nsecs_str
||
254 !age_str
|| !includes_count_str
)
256 err_printf( "invalid %s\n", hcachename
);
260 timestamp_init( &cachedata
.time
, atoi( object_str( time_secs_str
) ),
261 atoi( object_str( time_nsecs_str
) ) );
262 cachedata
.age
= atoi( object_str( age_str
) ) + 1;
264 count
= atoi( object_str( includes_count_str
) );
265 for ( l
= L0
, i
= 0; i
< count
; ++i
)
267 OBJECT
* const s
= read_netstring( f
);
270 err_printf( "invalid %s\n", hcachename
);
274 l
= list_push_back( l
, s
);
276 cachedata
.includes
= l
;
278 hdrscan_count_str
= read_netstring( f
);
279 if ( !hdrscan_count_str
)
281 err_printf( "invalid %s\n", hcachename
);
285 count
= atoi( object_str( hdrscan_count_str
) );
286 for ( l
= L0
, i
= 0; i
< count
; ++i
)
288 OBJECT
* const s
= read_netstring( f
);
291 err_printf( "invalid %s\n", hcachename
);
295 l
= list_push_back( l
, s
);
297 cachedata
.hdrscan
= l
;
299 c
= (HCACHEDATA
*)hash_insert( hcachehash
, cachedata
.boundname
, &found
)
303 c
->boundname
= cachedata
.boundname
;
304 c
->includes
= cachedata
.includes
;
305 c
->hdrscan
= cachedata
.hdrscan
;
306 c
->age
= cachedata
.age
;
307 timestamp_copy( &c
->time
, &cachedata
.time
);
311 err_printf( "can not insert header cache item, bailing on %s"
316 c
->next
= hcachelist
;
321 object_free( record_type
);
322 object_free( time_secs_str
);
323 object_free( time_nsecs_str
);
324 object_free( age_str
);
325 object_free( includes_count_str
);
326 object_free( hdrscan_count_str
);
331 if ( record_type
) object_free( record_type
);
332 if ( time_secs_str
) object_free( time_secs_str
);
333 if ( time_nsecs_str
) object_free( time_nsecs_str
);
334 if ( age_str
) object_free( age_str
);
335 if ( includes_count_str
) object_free( includes_count_str
);
336 if ( hdrscan_count_str
) object_free( hdrscan_count_str
);
338 if ( cachedata
.boundname
) object_free( cachedata
.boundname
);
339 if ( cachedata
.includes
) list_free( cachedata
.includes
);
340 if ( cachedata
.hdrscan
) list_free( cachedata
.hdrscan
);
346 out_printf( "hcache read from file %s\n", hcachename
);
350 object_free( version
);
359 int header_count
= 0;
360 const char * hcachename
;
366 if ( !( hcachename
= cache_name() ) )
369 if ( !( f
= fopen( hcachename
, "wb" ) ) )
371 err_printf( "[errno %d] failed to write hcache file '%s': %s",
372 errno
, hcachename
, strerror(errno
) );
376 maxage
= cache_maxage();
378 /* Print out the version. */
379 write_netstring( f
, CACHE_FILE_VERSION
);
382 for ( c
= hcachelist
; c
; c
= c
->next
)
386 char time_secs_str
[ 30 ];
387 char time_nsecs_str
[ 30 ];
389 char includes_count_str
[ 30 ];
390 char hdrscan_count_str
[ 30 ];
394 else if ( c
->age
> maxage
)
397 sprintf( includes_count_str
, "%lu", (long unsigned)list_length(
399 sprintf( hdrscan_count_str
, "%lu", (long unsigned)list_length(
401 sprintf( time_secs_str
, "%lu", (long unsigned)c
->time
.secs
);
402 sprintf( time_nsecs_str
, "%lu", (long unsigned)c
->time
.nsecs
);
403 sprintf( age_str
, "%lu", (long unsigned)c
->age
);
405 write_netstring( f
, CACHE_RECORD_HEADER
);
406 write_netstring( f
, object_str( c
->boundname
) );
407 write_netstring( f
, time_secs_str
);
408 write_netstring( f
, time_nsecs_str
);
409 write_netstring( f
, age_str
);
410 write_netstring( f
, includes_count_str
);
411 for ( iter
= list_begin( c
->includes
), end
= list_end( c
->includes
);
412 iter
!= end
; iter
= list_next( iter
) )
413 write_netstring( f
, object_str( list_item( iter
) ) );
414 write_netstring( f
, hdrscan_count_str
);
415 for ( iter
= list_begin( c
->hdrscan
), end
= list_end( c
->hdrscan
);
416 iter
!= end
; iter
= list_next( iter
) )
417 write_netstring( f
, object_str( list_item( iter
) ) );
421 write_netstring( f
, CACHE_RECORD_END
);
424 out_printf( "hcache written to %s. %d dependencies, %.0f%% hit rate\n",
425 hcachename
, header_count
, queries
? 100.0 * hits
/ queries
: 0 );
430 for ( c
= hcachelist
; c
; c
= c
->next
)
432 list_free( c
->includes
);
433 list_free( c
->hdrscan
);
434 object_free( c
->boundname
);
439 hashdone( hcachehash
);
444 LIST
* hcache( TARGET
* t
, int rec
, regexp
* re
[], LIST
* hdrscan
)
450 if ( ( c
= (HCACHEDATA
*)hash_find( hcachehash
, t
->boundname
) ) )
452 if ( !timestamp_cmp( &c
->time
, &t
->time
) )
454 LIST
* const l1
= hdrscan
;
455 LIST
* const l2
= c
->hdrscan
;
456 LISTITER iter1
= list_begin( l1
);
457 LISTITER
const end1
= list_end( l1
);
458 LISTITER iter2
= list_begin( l2
);
459 LISTITER
const end2
= list_end( l2
);
460 while ( iter1
!= end1
&& iter2
!= end2
)
462 if ( !object_equal( list_item( iter1
), list_item( iter2
) ) )
466 iter1
= list_next( iter1
);
467 iter2
= list_next( iter2
);
470 if ( iter1
!= end1
|| iter2
!= end2
)
474 out_printf( "HDRSCAN out of date in cache for %s\n",
475 object_str( t
->boundname
) );
476 out_printf(" real : ");
477 list_print( hdrscan
);
478 out_printf( "\n cached: " );
479 list_print( c
->hdrscan
);
483 list_free( c
->includes
);
484 list_free( c
->hdrscan
);
491 out_printf( "using header cache for %s\n", object_str(
495 return list_copy( c
->includes
);
501 out_printf ("header cache out of date for %s\n", object_str(
503 list_free( c
->includes
);
504 list_free( c
->hdrscan
);
512 c
= (HCACHEDATA
*)hash_insert( hcachehash
, t
->boundname
, &found
);
515 c
->boundname
= object_copy( t
->boundname
);
516 c
->next
= hcachelist
;
521 /* 'c' points at the cache entry. Its out of date. */
523 LIST
* const l
= headers1( L0
, t
->boundname
, rec
, re
);
525 timestamp_copy( &c
->time
, &t
->time
);
527 c
->includes
= list_copy( l
);
528 c
->hdrscan
= list_copy( hdrscan
);
534 #endif /* OPT_HEADER_CACHE_EXT */