resetting manifest requested domain to floor
[platform/upstream/ccache.git] / cleanup.c
1 /*
2  * Copyright (C) 2002-2006 Andrew Tridgell
3  * Copyright (C) 2009-2010 Joel Rosdahl
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 3 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 51
17  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19
20 #include "ccache.h"
21
22 /*
23  * When "max files" or "max cache size" is reached, one of the 16 cache
24  * subdirectories is cleaned up. When doing so, files are deleted (in LRU
25  * order) until the levels are below LIMIT_MULTIPLE.
26  */
27 #define LIMIT_MULTIPLE 0.8
28
29 static struct files {
30         char *fname;
31         time_t mtime;
32         size_t size; /* In KiB. */
33 } **files;
34 static unsigned allocated; /* Size of the files array. */
35 static unsigned num_files; /* Number of used entries in the files array. */
36
37 static size_t cache_size; /* In KiB. */
38 static size_t files_in_cache;
39 static size_t cache_size_threshold;
40 static size_t files_in_cache_threshold;
41
42 /* File comparison function that orders files in mtime order, oldest first. */
43 static int
44 files_compare(struct files **f1, struct files **f2)
45 {
46         if ((*f2)->mtime == (*f1)->mtime) {
47                 return strcmp((*f1)->fname, (*f2)->fname);
48         }
49         if ((*f2)->mtime > (*f1)->mtime) {
50                 return -1;
51         }
52         return 1;
53 }
54
55 /* this builds the list of files in the cache */
56 static void
57 traverse_fn(const char *fname, struct stat *st)
58 {
59         char *p;
60
61         if (!S_ISREG(st->st_mode)) return;
62
63         p = basename(fname);
64         if (str_eq(p, "stats")) {
65                 goto out;
66         }
67
68         if (str_startswith(p, ".nfs")) {
69                 /* Ignore temporary NFS files that may be left for open but deleted files. */
70                 goto out;
71         }
72
73         if (strstr(p, ".tmp.") != NULL) {
74                 /* delete any tmp files older than 1 hour */
75                 if (st->st_mtime + 3600 < time(NULL)) {
76                         x_unlink(fname);
77                         goto out;
78                 }
79         }
80
81         if (num_files == allocated) {
82                 allocated = 10000 + num_files*2;
83                 files = (struct files **)x_realloc(files, sizeof(struct files *)*allocated);
84         }
85
86         files[num_files] = (struct files *)x_malloc(sizeof(struct files));
87         files[num_files]->fname = x_strdup(fname);
88         files[num_files]->mtime = st->st_mtime;
89         files[num_files]->size = file_size(st) / 1024;
90         cache_size += files[num_files]->size;
91         files_in_cache++;
92         num_files++;
93
94 out:
95         free(p);
96 }
97
98 static void
99 delete_file(const char *path, size_t size)
100 {
101         if (x_unlink(path) == 0) {
102                 cache_size -= size;
103                 files_in_cache--;
104         } else if (errno != ENOENT) {
105                 cc_log("Failed to unlink %s (%s)", path, strerror(errno));
106         }
107 }
108
109 static void
110 delete_sibling_file(const char *base, const char *extension)
111 {
112         struct stat st;
113         char *path;
114
115         path = format("%s%s", base, extension);
116         if (lstat(path, &st) == 0) {
117                 delete_file(path, file_size(&st) / 1024);
118         } else if (errno != ENOENT) {
119                 cc_log("Failed to stat %s (%s)", path, strerror(errno));
120         }
121         free(path);
122 }
123
124 /* sort the files we've found and delete the oldest ones until we are
125    below the thresholds */
126 static void
127 sort_and_clean(void)
128 {
129         unsigned i;
130         const char *ext;
131         char *last_base = x_strdup("");
132
133         if (num_files > 1) {
134                 /* Sort in ascending mtime order. */
135                 qsort(files, num_files, sizeof(struct files *), (COMPAR_FN_T)files_compare);
136         }
137
138         /* delete enough files to bring us below the threshold */
139         for (i = 0; i < num_files; i++) {
140                 if ((cache_size_threshold == 0
141                      || cache_size <= cache_size_threshold)
142                     && (files_in_cache_threshold == 0
143                         || files_in_cache <= files_in_cache_threshold)) {
144                         break;
145                 }
146
147                 ext = get_extension(files[i]->fname);
148                 if (str_eq(ext, ".o")
149                     || str_eq(ext, ".d")
150                     || str_eq(ext, ".stderr")
151                     || str_eq(ext, "")) {
152                         char *base = remove_extension(files[i]->fname);
153                         if (!str_eq(base, last_base)) { /* Avoid redundant unlinks. */
154                                 /*
155                                  * Make sure that all sibling files are deleted so that a cached result
156                                  * is removed completely. Note the order of deletions -- the stderr
157                                  * file must be deleted last because if the ccache process gets killed
158                                  * after deleting the .stderr but before deleting the .o, the cached
159                                  * result would be inconsistent.
160                                  */
161                                 delete_sibling_file(base, ".o");
162                                 delete_sibling_file(base, ".d");
163                                 delete_sibling_file(base, ".stderr");
164                                 delete_sibling_file(base, ""); /* Object file from ccache 2.4. */
165                         }
166                         free(last_base);
167                         last_base = base;
168                 } else {
169                         /* .manifest or unknown file. */
170                         delete_file(files[i]->fname, files[i]->size);
171                 }
172         }
173         free(last_base);
174 }
175
176 /* cleanup in one cache subdir */
177 void
178 cleanup_dir(const char *dir, size_t maxfiles, size_t maxsize)
179 {
180         unsigned i;
181
182         cc_log("Cleaning up cache directory %s", dir);
183
184         cache_size_threshold = maxsize * LIMIT_MULTIPLE;
185         files_in_cache_threshold = maxfiles * LIMIT_MULTIPLE;
186
187         num_files = 0;
188         cache_size = 0;
189         files_in_cache = 0;
190
191         /* build a list of files */
192         traverse(dir, traverse_fn);
193
194         /* clean the cache */
195         sort_and_clean();
196
197         stats_set_sizes(dir, files_in_cache, cache_size);
198
199         /* free it up */
200         for (i = 0; i < num_files; i++) {
201                 free(files[i]->fname);
202                 free(files[i]);
203                 files[i] = NULL;
204         }
205         if (files) {
206                 free(files);
207         }
208         allocated = 0;
209         files = NULL;
210
211         num_files = 0;
212         cache_size = 0;
213         files_in_cache = 0;
214 }
215
216 /* cleanup in all cache subdirs */
217 void cleanup_all(const char *dir)
218 {
219         unsigned maxfiles, maxsize;
220         char *dname;
221         int i;
222
223         for (i = 0; i <= 0xF; i++) {
224                 dname = format("%s/%1x", dir, i);
225                 stats_get_limits(dname, &maxfiles, &maxsize);
226                 cleanup_dir(dname, maxfiles, maxsize);
227                 free(dname);
228         }
229 }
230
231 /* traverse function for wiping files */
232 static void wipe_fn(const char *fname, struct stat *st)
233 {
234         char *p;
235
236         if (!S_ISREG(st->st_mode)) return;
237
238         p = basename(fname);
239         if (str_eq(p, "stats")) {
240                 free(p);
241                 return;
242         }
243         free(p);
244
245         x_unlink(fname);
246 }
247
248 /* wipe all cached files in all subdirs */
249 void wipe_all(const char *dir)
250 {
251         char *dname;
252         int i;
253
254         for (i = 0; i <= 0xF; i++) {
255                 dname = format("%s/%1x", dir, i);
256                 traverse(dir, wipe_fn);
257                 free(dname);
258         }
259
260         /* and fix the counters */
261         cleanup_all(dir);
262 }