12
12
13
13
use digest:: Digest ;
14
14
use json;
15
+ use json:: ToJson ;
15
16
use sha1:: Sha1 ;
16
17
use serialize:: { Encoder , Encodable , Decoder , Decodable } ;
17
18
use arc:: { Arc , RWArc } ;
18
19
use treemap:: TreeMap ;
19
-
20
20
use std:: cell:: Cell ;
21
21
use std:: comm:: { PortOne , oneshot} ;
22
22
use std:: either:: { Either , Left , Right } ;
23
- use std:: io;
24
- use std:: run;
25
- use std:: task;
23
+ use std:: { io, os, task} ;
26
24
27
25
/**
28
26
*
@@ -107,11 +105,27 @@ impl WorkKey {
107
105
}
108
106
}
109
107
108
+ // FIXME #8883: The key should be a WorkKey and not a ~str.
109
+ // This is working around some JSON weirdness.
110
+ #[ deriving( Clone , Eq , Encodable , Decodable ) ]
111
+ struct WorkMap ( TreeMap < ~str , KindMap > ) ;
112
+
110
113
#[ deriving( Clone , Eq , Encodable , Decodable ) ]
111
- struct WorkMap ( TreeMap < WorkKey , ~str > ) ;
114
+ struct KindMap ( TreeMap < ~ str , ~str > ) ;
112
115
113
116
impl WorkMap {
114
117
fn new ( ) -> WorkMap { WorkMap ( TreeMap :: new ( ) ) }
118
+
119
+ fn insert_work_key ( & mut self , k : WorkKey , val : ~str ) {
120
+ let WorkKey { kind, name } = k;
121
+ match self . find_mut ( & name) {
122
+ Some ( & KindMap ( ref mut m) ) => { m. insert ( kind, val) ; return ; }
123
+ None => ( )
124
+ }
125
+ let mut new_map = TreeMap :: new ( ) ;
126
+ new_map. insert ( kind, val) ;
127
+ self . insert ( name, KindMap ( new_map) ) ;
128
+ }
115
129
}
116
130
117
131
struct Database {
@@ -123,11 +137,15 @@ struct Database {
123
137
impl Database {
124
138
125
139
pub fn new ( p : Path ) -> Database {
126
- Database {
140
+ let mut rslt = Database {
127
141
db_filename : p,
128
142
db_cache : TreeMap :: new ( ) ,
129
143
db_dirty : false
144
+ } ;
145
+ if os:: path_exists ( & rslt. db_filename ) {
146
+ rslt. load ( ) ;
130
147
}
148
+ rslt
131
149
}
132
150
133
151
pub fn prepare ( & self ,
@@ -154,6 +172,41 @@ impl Database {
154
172
self . db_cache . insert ( k, v) ;
155
173
self . db_dirty = true
156
174
}
175
+
176
+ // FIXME #4330: This should have &mut self and should set self.db_dirty to false.
177
+ fn save ( & self ) {
178
+ let f = io:: file_writer ( & self . db_filename , [ io:: Create , io:: Truncate ] ) . unwrap ( ) ;
179
+ self . db_cache . to_json ( ) . to_pretty_writer ( f) ;
180
+ }
181
+
182
+ fn load ( & mut self ) {
183
+ assert ! ( !self . db_dirty) ;
184
+ assert ! ( os:: path_exists( & self . db_filename) ) ;
185
+ let f = io:: file_reader ( & self . db_filename ) ;
186
+ match f {
187
+ Err ( e) => fail ! ( "Couldn't load workcache database %s: %s" ,
188
+ self . db_filename. to_str( ) , e. to_str( ) ) ,
189
+ Ok ( r) =>
190
+ match json:: from_reader ( r) {
191
+ Err ( e) => fail ! ( "Couldn't parse workcache database (from file %s): %s" ,
192
+ self . db_filename. to_str( ) , e. to_str( ) ) ,
193
+ Ok ( r) => {
194
+ let mut decoder = json:: Decoder ( r) ;
195
+ self . db_cache = Decodable :: decode ( & mut decoder) ;
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+
202
+ // FIXME #4330: use &mut self here
203
+ #[ unsafe_destructor]
204
+ impl Drop for Database {
205
+ fn drop ( & self ) {
206
+ if self . db_dirty {
207
+ self . save ( ) ;
208
+ }
209
+ }
157
210
}
158
211
159
212
struct Logger {
@@ -172,12 +225,20 @@ impl Logger {
172
225
}
173
226
}
174
227
228
+ type FreshnessMap = TreeMap<~str,extern fn(&str,&str)->bool>;
229
+
175
230
#[deriving(Clone)]
176
231
struct Context {
177
232
db: RWArc<Database>,
178
233
logger: RWArc<Logger>,
179
234
cfg: Arc<json::Object>,
180
- freshness: Arc<TreeMap<~str,extern fn(&str,&str)->bool>>
235
+ /// Map from kinds (source, exe, url, etc.) to a freshness function.
236
+ /// The freshness function takes a name (e.g. file path) and value
237
+ /// (e.g. hash of file contents) and determines whether it's up-to-date.
238
+ /// For example, in the file case, this would read the file off disk,
239
+ /// hash it, and return the result of comparing the given hash and the
240
+ /// read hash for equality.
241
+ freshness: Arc<FreshnessMap>
181
242
}
182
243
183
244
struct Prep<'self> {
@@ -205,6 +266,7 @@ fn json_encode<T:Encodable<json::Encoder>>(t: &T) -> ~str {
205
266
206
267
// FIXME(#5121)
207
268
fn json_decode<T:Decodable<json::Decoder>>(s: &str) -> T {
269
+ debug!(" json decoding: %s", s) ;
208
270
do io:: with_str_reader ( s) |rdr| {
209
271
let j = json:: from_reader ( rdr) . unwrap ( ) ;
210
272
let mut decoder = json:: Decoder ( j) ;
@@ -230,11 +292,18 @@ impl Context {
230
292
pub fn new ( db : RWArc < Database > ,
231
293
lg : RWArc < Logger > ,
232
294
cfg : Arc < json:: Object > ) -> Context {
295
+ Context :: new_with_freshness ( db, lg, cfg, Arc :: new ( TreeMap :: new ( ) ) )
296
+ }
297
+
298
+ pub fn new_with_freshness ( db : RWArc < Database > ,
299
+ lg : RWArc < Logger > ,
300
+ cfg : Arc < json:: Object > ,
301
+ freshness : Arc < FreshnessMap > ) -> Context {
233
302
Context {
234
303
db : db,
235
304
logger : lg,
236
305
cfg : cfg,
237
- freshness: Arc::new(TreeMap::new())
306
+ freshness : freshness
238
307
}
239
308
}
240
309
@@ -249,6 +318,35 @@ impl Context {
249
318
250
319
}
251
320
321
+ impl Exec {
322
+ pub fn discover_input ( & mut self , dependency_kind : & str ,
323
+ // Discovered input
324
+ dependency_name : & str , dependency_val : & str ) {
325
+ debug ! ( "Discovering input %s %s %s" , dependency_kind, dependency_name, dependency_val) ;
326
+ self . discovered_inputs . insert_work_key ( WorkKey :: new ( dependency_kind, dependency_name) ,
327
+ dependency_val. to_owned ( ) ) ;
328
+ }
329
+ pub fn discover_output ( & mut self , dependency_kind : & str ,
330
+ // Discovered output
331
+ dependency_name : & str , dependency_val : & str ) {
332
+ debug ! ( "Discovering output %s %s %s" , dependency_kind, dependency_name, dependency_val) ;
333
+ self . discovered_outputs . insert_work_key ( WorkKey :: new ( dependency_kind, dependency_name) ,
334
+ dependency_val. to_owned ( ) ) ;
335
+ }
336
+
337
+ // returns pairs of (kind, name)
338
+ pub fn lookup_discovered_inputs ( & self ) -> ~[ ( ~str , ~str ) ] {
339
+ let mut rs = ~[ ] ;
340
+ for ( k, v) in self . discovered_inputs . iter ( ) {
341
+ for ( k1, _) in v. iter ( ) {
342
+ rs. push ( ( k1. clone ( ) , k. clone ( ) ) ) ;
343
+ }
344
+ }
345
+ rs
346
+ }
347
+
348
+ }
349
+
252
350
impl < ' self > Prep < ' self > {
253
351
fn new ( ctxt : & ' self Context , fn_name : & ' self str ) -> Prep < ' self > {
254
352
Prep {
@@ -257,18 +355,30 @@ impl<'self> Prep<'self> {
257
355
declared_inputs : WorkMap :: new ( )
258
356
}
259
357
}
358
+
359
+ pub fn lookup_declared_inputs ( & self ) -> ~[ ~str ] {
360
+ let mut rs = ~[ ] ;
361
+ for ( _, v) in self . declared_inputs . iter ( ) {
362
+ for ( inp, _) in v. iter ( ) {
363
+ rs. push ( inp. clone ( ) ) ;
364
+ }
365
+ }
366
+ rs
367
+ }
260
368
}
261
369
262
370
impl < ' self > Prep < ' self > {
263
- fn declare_input(&mut self, kind:&str, name:&str, val:&str) {
264
- self.declared_inputs.insert(WorkKey::new(kind, name),
371
+ pub fn declare_input ( & mut self , kind : & str , name : & str , val : & str ) {
372
+ debug ! ( "Declaring input %s %s %s" , kind, name, val) ;
373
+ self . declared_inputs . insert_work_key ( WorkKey :: new ( kind, name) ,
265
374
val. to_owned ( ) ) ;
266
375
}
267
376
268
377
fn is_fresh ( & self , cat : & str , kind : & str ,
269
378
name : & str , val : & str ) -> bool {
270
379
let k = kind. to_owned ( ) ;
271
380
let f = self . ctxt . freshness . get ( ) . find ( & k) ;
381
+ debug ! ( "freshness for: %s/%s/%s/%s" , cat, kind, name, val)
272
382
let fresh = match f {
273
383
None => fail ! ( "missing freshness-function for '%s'" , kind) ,
274
384
Some ( f) => ( * f) ( name, val)
@@ -286,27 +396,31 @@ impl<'self> Prep<'self> {
286
396
}
287
397
288
398
fn all_fresh ( & self , cat : & str , map : & WorkMap ) -> bool {
289
- for ( k, v) in map. iter ( ) {
290
- if ! self . is_fresh ( cat, k. kind , k. name , * v) {
291
- return false ;
399
+ for ( k_name, kindmap) in map. iter ( ) {
400
+ for ( k_kind, v) in kindmap. iter ( ) {
401
+ if ! self . is_fresh ( cat, * k_kind, * k_name, * v) {
402
+ return false ;
292
403
}
404
+ }
293
405
}
294
406
return true ;
295
407
}
296
408
297
- fn exec < T : Send +
409
+ pub fn exec < T : Send +
298
410
Encodable < json:: Encoder > +
299
411
Decodable < json:: Decoder > > (
300
- & ' self self , blk : ~fn ( & Exec ) -> T ) -> T {
412
+ & ' self self , blk : ~fn ( & mut Exec ) -> T ) -> T {
301
413
self . exec_work ( blk) . unwrap ( )
302
414
}
303
415
304
416
fn exec_work< T : Send +
305
417
Encodable < json:: Encoder > +
306
418
Decodable < json:: Decoder > > ( // FIXME(#5121)
307
- & ' self self , blk : ~fn ( & Exec ) -> T ) -> Work < ' self , T > {
419
+ & ' self self , blk : ~fn ( & mut Exec ) -> T ) -> Work < ' self , T > {
308
420
let mut bo = Some ( blk) ;
309
421
422
+ debug ! ( "exec_work: looking up %s and %?" , self . fn_name,
423
+ self . declared_inputs) ;
310
424
let cached = do self . ctxt . db . read |db| {
311
425
db. prepare ( self . fn_name , & self . declared_inputs )
312
426
} ;
@@ -316,21 +430,26 @@ impl<'self> Prep<'self> {
316
430
if self . all_fresh ( "declared input" , & self . declared_inputs ) &&
317
431
self . all_fresh ( "discovered input" , disc_in) &&
318
432
self . all_fresh ( "discovered output" , disc_out) => {
433
+ debug ! ( "Cache hit!" ) ;
434
+ debug ! ( "Trying to decode: %? / %? / %?" ,
435
+ disc_in, disc_out, * res) ;
319
436
Left ( json_decode ( * res) )
320
437
}
321
438
322
439
_ => {
440
+ debug ! ( "Cache miss!" ) ;
323
441
let ( port, chan) = oneshot ( ) ;
324
442
let blk = bo. take_unwrap ( ) ;
325
443
let chan = Cell :: new ( chan) ;
326
444
445
+ // What happens if the task fails?
327
446
do task:: spawn {
328
- let exe = Exec {
447
+ let mut exe = Exec {
329
448
discovered_inputs : WorkMap :: new ( ) ,
330
449
discovered_outputs : WorkMap :: new ( ) ,
331
450
} ;
332
451
let chan = chan. take ( ) ;
333
- let v = blk ( & exe) ;
452
+ let v = blk ( & mut exe) ;
334
453
chan. send ( ( exe, v) ) ;
335
454
}
336
455
Right ( port)
@@ -371,9 +490,10 @@ impl<'self, T:Send +
371
490
}
372
491
373
492
374
- // #[test]
493
+ #[ test]
375
494
fn test( ) {
376
495
use std:: io:: WriterUtil ;
496
+ use std:: run;
377
497
378
498
let pth = Path ( "foo.c" ) ;
379
499
{
0 commit comments