1212
1313use digest:: Digest ;
1414use json;
15+ use json:: ToJson ;
1516use sha1:: Sha1 ;
1617use serialize:: { Encoder , Encodable , Decoder , Decodable } ;
1718use arc:: { Arc , RWArc } ;
1819use treemap:: TreeMap ;
19-
2020use std:: cell:: Cell ;
2121use std:: comm:: { PortOne , oneshot} ;
2222use std:: either:: { Either , Left , Right } ;
23- use std:: io;
24- use std:: run;
25- use std:: task;
23+ use std:: { io, os, task} ;
2624
2725/**
2826*
@@ -107,11 +105,27 @@ impl WorkKey {
107105 }
108106}
109107
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+
110113#[ deriving( Clone , Eq , Encodable , Decodable ) ]
111- struct WorkMap ( TreeMap < WorkKey , ~str > ) ;
114+ struct KindMap ( TreeMap < ~ str , ~str > ) ;
112115
113116impl WorkMap {
114117 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+ }
115129}
116130
117131struct Database {
@@ -123,11 +137,15 @@ struct Database {
123137impl Database {
124138
125139 pub fn new ( p : Path ) -> Database {
126- Database {
140+ let mut rslt = Database {
127141 db_filename : p,
128142 db_cache : TreeMap :: new ( ) ,
129143 db_dirty : false
144+ } ;
145+ if os:: path_exists ( & rslt. db_filename ) {
146+ rslt. load ( ) ;
130147 }
148+ rslt
131149 }
132150
133151 pub fn prepare ( & self ,
@@ -154,6 +172,41 @@ impl Database {
154172 self . db_cache . insert ( k, v) ;
155173 self . db_dirty = true
156174 }
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+ }
157210}
158211
159212struct Logger {
@@ -172,12 +225,20 @@ impl Logger {
172225 }
173226}
174227
228+ type FreshnessMap = TreeMap<~str,extern fn(&str,&str)->bool>;
229+
175230#[deriving(Clone)]
176231struct Context {
177232 db: RWArc<Database>,
178233 logger: RWArc<Logger>,
179234 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>
181242}
182243
183244struct Prep<'self> {
@@ -205,6 +266,7 @@ fn json_encode<T:Encodable<json::Encoder>>(t: &T) -> ~str {
205266
206267// FIXME(#5121)
207268fn json_decode<T:Decodable<json::Decoder>>(s: &str) -> T {
269+ debug!(" json decoding: %s", s) ;
208270 do io:: with_str_reader ( s) |rdr| {
209271 let j = json:: from_reader ( rdr) . unwrap ( ) ;
210272 let mut decoder = json:: Decoder ( j) ;
@@ -230,11 +292,18 @@ impl Context {
230292 pub fn new ( db : RWArc < Database > ,
231293 lg : RWArc < Logger > ,
232294 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 {
233302 Context {
234303 db : db,
235304 logger : lg,
236305 cfg : cfg,
237- freshness: Arc::new(TreeMap::new())
306+ freshness : freshness
238307 }
239308 }
240309
@@ -249,6 +318,35 @@ impl Context {
249318
250319}
251320
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+
252350impl < ' self > Prep < ' self > {
253351 fn new ( ctxt : & ' self Context , fn_name : & ' self str ) -> Prep < ' self > {
254352 Prep {
@@ -257,18 +355,30 @@ impl<'self> Prep<'self> {
257355 declared_inputs : WorkMap :: new ( )
258356 }
259357 }
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+ }
260368}
261369
262370impl < ' 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) ,
265374 val. to_owned ( ) ) ;
266375 }
267376
268377 fn is_fresh ( & self , cat : & str , kind : & str ,
269378 name : & str , val : & str ) -> bool {
270379 let k = kind. to_owned ( ) ;
271380 let f = self . ctxt . freshness . get ( ) . find ( & k) ;
381+ debug ! ( "freshness for: %s/%s/%s/%s" , cat, kind, name, val)
272382 let fresh = match f {
273383 None => fail ! ( "missing freshness-function for '%s'" , kind) ,
274384 Some ( f) => ( * f) ( name, val)
@@ -286,27 +396,31 @@ impl<'self> Prep<'self> {
286396 }
287397
288398 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 ;
292403 }
404+ }
293405 }
294406 return true ;
295407 }
296408
297- fn exec < T : Send +
409+ pub fn exec < T : Send +
298410 Encodable < json:: Encoder > +
299411 Decodable < json:: Decoder > > (
300- & ' self self , blk : ~fn ( & Exec ) -> T ) -> T {
412+ & ' self self , blk : ~fn ( & mut Exec ) -> T ) -> T {
301413 self . exec_work ( blk) . unwrap ( )
302414 }
303415
304416 fn exec_work< T : Send +
305417 Encodable < json:: Encoder > +
306418 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 > {
308420 let mut bo = Some ( blk) ;
309421
422+ debug ! ( "exec_work: looking up %s and %?" , self . fn_name,
423+ self . declared_inputs) ;
310424 let cached = do self . ctxt . db . read |db| {
311425 db. prepare ( self . fn_name , & self . declared_inputs )
312426 } ;
@@ -316,21 +430,26 @@ impl<'self> Prep<'self> {
316430 if self . all_fresh ( "declared input" , & self . declared_inputs ) &&
317431 self . all_fresh ( "discovered input" , disc_in) &&
318432 self . all_fresh ( "discovered output" , disc_out) => {
433+ debug ! ( "Cache hit!" ) ;
434+ debug ! ( "Trying to decode: %? / %? / %?" ,
435+ disc_in, disc_out, * res) ;
319436 Left ( json_decode ( * res) )
320437 }
321438
322439 _ => {
440+ debug ! ( "Cache miss!" ) ;
323441 let ( port, chan) = oneshot ( ) ;
324442 let blk = bo. take_unwrap ( ) ;
325443 let chan = Cell :: new ( chan) ;
326444
445+ // What happens if the task fails?
327446 do task:: spawn {
328- let exe = Exec {
447+ let mut exe = Exec {
329448 discovered_inputs : WorkMap :: new ( ) ,
330449 discovered_outputs : WorkMap :: new ( ) ,
331450 } ;
332451 let chan = chan. take ( ) ;
333- let v = blk ( & exe) ;
452+ let v = blk ( & mut exe) ;
334453 chan. send ( ( exe, v) ) ;
335454 }
336455 Right ( port)
@@ -371,9 +490,10 @@ impl<'self, T:Send +
371490}
372491
373492
374- // #[test]
493+ #[ test]
375494fn test( ) {
376495 use std:: io:: WriterUtil ;
496+ use std:: run;
377497
378498 let pth = Path ( "foo.c" ) ;
379499 {
0 commit comments