1
2 /******************************************************************************
3 * MODULE : data_cache.cpp
4 * DESCRIPTION: utilities for caching data
5 * COPYRIGHT : (C) 2005 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11
12 #include "data_cache.hpp"
13 #include "file.hpp"
14 #include "convert.hpp"
15 #include "iterator.hpp"
16
17 /******************************************************************************
18 * Caching routines
19 ******************************************************************************/
20
21 static hashmap<tree,tree> cache_data ("?");
22 static hashset<string> cache_loaded;
23 static hashset<string> cache_changed;
24 static hashmap<string,bool> cache_valid (false);
25
26 void
cache_set(string buffer,tree key,tree t)27 cache_set (string buffer, tree key, tree t) {
28 tree ckey= tuple (buffer, key);
29 if (cache_data[ckey] != t) {
30 cache_data (ckey)= t;
31 cache_changed->insert (buffer);
32 }
33 }
34
35 void
cache_reset(string buffer,tree key)36 cache_reset (string buffer, tree key) {
37 tree ckey= tuple (buffer, key);
38 cache_data->reset (ckey);
39 cache_changed->insert (buffer);
40 }
41
42 bool
is_cached(string buffer,tree key)43 is_cached (string buffer, tree key) {
44 tree ckey= tuple (buffer, key);
45 return cache_data->contains (ckey);
46 }
47
48 tree
cache_get(string buffer,tree key)49 cache_get (string buffer, tree key) {
50 tree ckey= tuple (buffer, key);
51 return cache_data [ckey];
52 }
53
54 bool
is_up_to_date(url dir)55 is_up_to_date (url dir) {
56 string name_dir= concretize (dir);
57 if (cache_valid->contains (name_dir)) return cache_valid [name_dir];
58 int l= last_modified (dir, false);
59 if (is_cached ("validate_cache.scm", name_dir)) {
60 int r= as_int (cache_get ("validate_cache.scm", name_dir) -> label);
61 if (l == r) {
62 cache_valid (name_dir)= true;
63 return true;
64 }
65 //cout << name_dir << " no longer up to date " << r << " -> " << l << "\n";
66 }
67 //else cout << name_dir << " not up to date " << l << "\n";
68 cache_set ("validate_cache.scm", name_dir, as_string (l));
69 cache_valid (name_dir)= false;
70 // FIXME: we should explicitly remove all data concerning files in 'dir'
71 // from the various caches. Indeed, at a next run of TeXmacs, the directory
72 // will be regarded as up to date, but the other caches may still contain
73 // outdated data. Careful: invalidating the cache lines should not
74 // give rise to a performance penaly (e.g. go through all entries of
75 // 'cache_data', or reloading unchanged files many times).
76 // See also 'declare_out_of_date'.
77 return false;
78 }
79
80 bool
is_recursively_up_to_date(url dir)81 is_recursively_up_to_date (url dir) {
82 if (!is_up_to_date (dir)) return false;
83 bool error_flag;
84 array<string> a= read_directory (dir, error_flag);
85 for (int i=0; i<N(a); i++)
86 if (url (a[i]) != url_here () && url (a[i]) != url_parent ())
87 if (N(a[i])>0 && a[i][0] != '.')
88 if (is_directory (dir * a[i]))
89 if (!is_recursively_up_to_date (dir * a[i]))
90 return false;
91 return true;
92 }
93
94 void
declare_out_of_date(url dir)95 declare_out_of_date (url dir) {
96 //cout << "out of date: " << dir << "\n";
97 string name_dir= concretize (dir);
98 int l= last_modified (dir, false);
99 cache_set ("validate_cache.scm", name_dir, as_string (l));
100 cache_valid (name_dir)= false;
101 // FIXME: see 'FIXME' in 'is_up_to_date'.
102 }
103
104 /******************************************************************************
105 * Which files should be stored in the cache?
106 ******************************************************************************/
107
108 static url texmacs_path (url_none ());
109 static url texmacs_doc_path (url_none ());
110 static url texmacs_home_path (url_none ());
111
112 static string texmacs_path_string;
113 static string texmacs_doc_path_string;
114 static string texmacs_home_path_string;
115 static string texmacs_font_path_string;
116
117 bool
do_cache_dir(string name)118 do_cache_dir (string name) {
119 return
120 starts (name, texmacs_path_string) ||
121 starts (name, texmacs_doc_path_string);
122 }
123
124 bool
do_cache_stat(string name)125 do_cache_stat (string name) {
126 return
127 starts (name, texmacs_path_string) ||
128 starts (name, texmacs_font_path_string) ||
129 starts (name, texmacs_doc_path_string);
130 }
131
132 bool
do_cache_stat_fail(string name)133 do_cache_stat_fail (string name) {
134 return
135 !ends (name, ".ts") &&
136 (starts (name, texmacs_path_string) ||
137 starts (name, texmacs_doc_path_string));
138 }
139
140 bool
do_cache_file(string name)141 do_cache_file (string name) {
142 return
143 !ends (name, ".ts") &&
144 (starts (name, texmacs_path_string) ||
145 starts (name, texmacs_font_path_string));
146 }
147
148 bool
do_cache_doc(string name)149 do_cache_doc (string name) {
150 return starts (name, texmacs_doc_path_string);
151 }
152
153 /******************************************************************************
154 * Saving and loading the cache to/from disk
155 ******************************************************************************/
156
157 void
cache_save(string buffer)158 cache_save (string buffer) {
159 if (cache_changed->contains (buffer)) {
160 url cache_file= texmacs_home_path * url ("system/cache/" * buffer);
161 string cached;
162 iterator<tree> it= iterate (cache_data);
163 if (buffer == "file_cache" || buffer == "doc_cache") {
164 while (it->busy ()) {
165 tree ckey= it->next ();
166 if (ckey[0] == buffer) {
167 cached << ckey[1]->label << "\n";
168 cached << cache_data [ckey]->label << "\n";
169 cached << "%-%-tm-cache-%-%\n";
170 }
171 }
172 }
173 else {
174 cached << "(tuple\n";
175 while (it->busy ()) {
176 tree ckey= it->next ();
177 if (ckey[0] == buffer) {
178 cached << tree_to_scheme (ckey[1]) << " ";
179 cached << tree_to_scheme (cache_data [ckey]) << "\n";
180 }
181 }
182 cached << ")";
183 }
184 (void) save_string (cache_file, cached);
185 cache_changed->remove (buffer);
186 }
187 }
188
189 void
cache_load(string buffer)190 cache_load (string buffer) {
191 if (!cache_loaded->contains (buffer)) {
192 url cache_file = texmacs_home_path * url ("system/cache/" * buffer);
193 //cout << "cache_file "<< cache_file << LF;
194 string cached;
195 if (!load_string (cache_file, cached, false)) {
196 if (buffer == "file_cache" || buffer == "doc_cache") {
197 int i=0, n= N(cached);
198 while (i<n) {
199 int start= i;
200 while (i<n && cached[i] != '\n') i++;
201 string key= cached (start, i);
202 i++; start= i;
203 while (i<n && (cached[i] != '\n' ||
204 !test (cached, i+1, "%-%-tm-cache-%-%"))) i++;
205 string im= cached (start, i);
206 i++;
207 while (i<n && cached[i] != '\n') i++;
208 i++;
209 //cout << "key= " << key << "\n----------------------\n";
210 //cout << "im= " << im << "\n----------------------\n";
211 cache_data (tuple (buffer, key))= im;
212 }
213 }
214 else {
215 tree t= scheme_to_tree (cached);
216 for (int i=0; i<N(t)-1; i+=2)
217 cache_data (tuple (buffer, t[i]))= t[i+1];
218 }
219 }
220 cache_loaded->insert (buffer);
221 }
222 }
223
224 void
cache_memorize()225 cache_memorize () {
226 cache_save ("file_cache");
227 cache_save ("doc_cache");
228 cache_save ("dir_cache.scm");
229 cache_save ("stat_cache.scm");
230 cache_save ("font_cache.scm");
231 cache_save ("validate_cache.scm");
232 }
233
234 void
cache_refresh()235 cache_refresh () {
236 cache_data = hashmap<tree,tree> ("?");
237 cache_loaded = hashset<string> ();
238 cache_changed= hashset<string> ();
239 cache_load ("file_cache");
240 cache_load ("dir_cache.scm");
241 cache_load ("stat_cache.scm");
242 cache_load ("font_cache.scm");
243 cache_load ("validate_cache.scm");
244 }
245
246 void
cache_initialize()247 cache_initialize () {
248 texmacs_path= url_system ("$TEXMACS_PATH");
249 if (get_env ("TEXMACS_HOME_PATH") == "")
250 texmacs_home_path= url_system ("$HOME/.TeXmacs");
251 else texmacs_home_path= url_system ("$TEXMACS_HOME_PATH");
252 if (get_env ("TEXMACS_DOC_PATH") == "")
253 texmacs_doc_path= url_system ("$TEXMACS_PATH/doc");
254 else texmacs_doc_path= url_system ("$TEXMACS_DOC_PATH");
255
256 texmacs_path_string = concretize (texmacs_path);
257 texmacs_home_path_string = concretize (texmacs_home_path);
258 texmacs_doc_path_string = concretize (texmacs_doc_path);
259 texmacs_font_path_string = concretize (texmacs_home_path * "fonts/");
260
261 cache_refresh ();
262 if (is_recursively_up_to_date (texmacs_path * "fonts/type1") &&
263 is_recursively_up_to_date (texmacs_path * "fonts/truetype") &&
264 is_recursively_up_to_date (texmacs_home_path * "fonts/type1") &&
265 is_recursively_up_to_date (texmacs_home_path * "fonts/truetype"));
266 else remove (texmacs_home_path * "fonts/error" * url_wildcard ("*"));
267 }
268