| author | haftmann | 
| Tue, 27 Apr 2010 08:18:25 +0200 | |
| changeset 36413 | 942438a0fa84 | 
| parent 36086 | 8e5454761f26 | 
| child 37740 | 9bb4a74cff4e | 
| permissions | -rw-r--r-- | 
| 35942 
667fd8553cd5
use internal SHA1 digest implementation for generating hash keys
 boehmes parents: 
35941diff
changeset | 1 | (* Title: Tools/cache_io.ML | 
| 35151 | 2 | Author: Sascha Boehme, TU Muenchen | 
| 3 | ||
| 4 | Cache for output of external processes. | |
| 5 | *) | |
| 6 | ||
| 7 | signature CACHE_IO = | |
| 8 | sig | |
| 9 | val with_tmp_file: string -> (Path.T -> 'a) -> 'a | |
| 36086 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 10 | val run: (Path.T -> Path.T -> string) -> string -> string list * string list | 
| 35151 | 11 | |
| 12 | type cache | |
| 13 | val make: Path.T -> cache | |
| 14 | val cache_path_of: cache -> Path.T | |
| 36086 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 15 | val lookup: cache -> string -> (string list * string list) option * string | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 16 | val run_and_cache: cache -> string -> (Path.T -> Path.T -> string) -> | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 17 | string -> string list * string list | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 18 | val run_cached: cache -> (Path.T -> Path.T -> string) -> string -> | 
| 35151 | 19 | string list * string list | 
| 20 | end | |
| 21 | ||
| 22 | structure Cache_IO : CACHE_IO = | |
| 23 | struct | |
| 24 | ||
| 36086 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 25 | val cache_io_prefix = "cache-io-" | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 26 | |
| 35151 | 27 | fun with_tmp_file name f = | 
| 28 | let | |
| 29 | val path = File.tmp_path (Path.explode (name ^ serial_string ())) | |
| 30 | val x = Exn.capture f path | |
| 31 | val _ = try File.rm path | |
| 32 | in Exn.release x end | |
| 33 | ||
| 36086 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 34 | fun run make_cmd str = | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 35 | with_tmp_file cache_io_prefix (fn in_path => | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 36 | with_tmp_file cache_io_prefix (fn out_path => | 
| 35151 | 37 | let | 
| 36086 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 38 | val _ = File.write in_path str | 
| 35151 | 39 | val (out2, _) = bash_output (make_cmd in_path out_path) | 
| 40 | val out1 = the_default [] (try (rev o File.fold_lines cons out_path) []) | |
| 36086 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 41 | in (out1, split_lines out2) end)) | 
| 35151 | 42 | |
| 43 | ||
| 44 | ||
| 45 | abstype cache = Cache of {
 | |
| 46 | path: Path.T, | |
| 47 | table: (int * (int * int * int) Symtab.table) Synchronized.var } | |
| 48 | with | |
| 49 | ||
| 50 | ||
| 51 | fun cache_path_of (Cache {path, ...}) = path
 | |
| 52 | ||
| 53 | ||
| 54 | fun load cache_path = | |
| 55 | let | |
| 56 |     fun err () = error ("Cache IO: corrupted cache file: " ^
 | |
| 57 | File.shell_path cache_path) | |
| 58 | ||
| 59 | fun int_of_string s = | |
| 60 | (case read_int (explode s) of | |
| 61 | (i, []) => i | |
| 62 | | _ => err ()) | |
| 63 | ||
| 64 | fun split line = | |
| 65 | (case space_explode " " line of | |
| 66 | [key, len1, len2] => (key, int_of_string len1, int_of_string len2) | |
| 67 | | _ => err ()) | |
| 68 | ||
| 69 | fun parse line ((i, l), tab) = | |
| 70 | if i = l | |
| 71 | then | |
| 72 | let val (key, l1, l2) = split line | |
| 73 | in ((i+1, l+l1+l2+1), Symtab.update (key, (i+1, l1, l2)) tab) end | |
| 74 | else ((i+1, l), tab) | |
| 75 | in apfst fst (File.fold_lines parse cache_path ((1, 1), Symtab.empty)) end | |
| 76 | ||
| 77 | fun make path = | |
| 78 | let val table = if File.exists path then load path else (1, Symtab.empty) | |
| 79 |   in Cache {path=path, table=Synchronized.var (Path.implode path) table} end
 | |
| 80 | ||
| 81 | ||
| 82 | fun load_cached_result cache_path (p, len1, len2) = | |
| 83 | let | |
| 84 | fun load line (i, xsp) = | |
| 85 | if i < p then (i+1, xsp) | |
| 86 | else if i < p + len1 then (i+1, apfst (cons line) xsp) | |
| 87 | else if i < p + len2 then (i+1, apsnd (cons line) xsp) | |
| 88 | else (i, xsp) | |
| 89 | in pairself rev (snd (File.fold_lines load cache_path (1, ([], [])))) end | |
| 90 | ||
| 36086 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 91 | |
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 92 | fun lookup (Cache {path=cache_path, table}) str =
 | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 93 | let val key = SHA1.digest str | 
| 35151 | 94 | in | 
| 95 | (case Symtab.lookup (snd (Synchronized.value table)) key of | |
| 36086 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 96 | NONE => (NONE, key) | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 97 | | SOME pos => (SOME (load_cached_result cache_path pos), key)) | 
| 35151 | 98 | end | 
| 99 | ||
| 36086 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 100 | |
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 101 | fun run_and_cache (Cache {path=cache_path, table}) key make_cmd str =
 | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 102 | let | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 103 | val res as (out, err) = run make_cmd str | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 104 | val (l1, l2) = pairself length res | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 105 | val header = key ^ " " ^ string_of_int l1 ^ " " ^ string_of_int l2 | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 106 | val lines = map (suffix "\n") (header :: out @ err) | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 107 | |
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 108 | val _ = Synchronized.change table (fn (p, tab) => | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 109 | if Symtab.defined tab key then (p, tab) | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 110 | else | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 111 | let val _ = File.append_list cache_path lines | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 112 | in (p+l1+l2+1, Symtab.update (key, (p+1, l1, l2)) tab) end) | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 113 | in res end | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 114 | |
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 115 | |
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 116 | fun run_cached cache make_cmd str = | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 117 | (case lookup cache str of | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 118 | (NONE, key) => run_and_cache cache key make_cmd str | 
| 
8e5454761f26
simplified Cache_IO interface (input is just a string and not already stored in a file)
 boehmes parents: 
35942diff
changeset | 119 | | (SOME output, _) => output) | 
| 35151 | 120 | |
| 121 | end | |
| 122 | end |